mirror of
https://github.com/QuiteAFancyEmerald/Holy-Unblocker.git
synced 2025-05-16 05:00:02 -04:00
Reuploaded
This commit is contained in:
parent
f47fff81c8
commit
bed679d92a
722 changed files with 62888 additions and 0 deletions
78
README.md
Normal file
78
README.md
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Alloy Proxy
|
||||
|
||||
A node.js proxy that features URL encoding, and amazing compatablity!
|
||||
|
||||
[](https://heroku.com/deploy?template=https://github.com/titaniumnetwork-dev/alloyproxy/)
|
||||
|
||||
# How to install and use:
|
||||
|
||||
`git clone https://github.com/titaniumnetwork-dev/alloyproxy.git`
|
||||
|
||||
`cd alloyproxy`
|
||||
|
||||
`npm install`
|
||||
|
||||
`npm start`
|
||||
|
||||
The default place for the proxy when its started is `http://localhost:8080` but feel free to change it in config.json!
|
||||
|
||||
# How the proxy works:
|
||||
|
||||
The proxy works by using node-fetch (Basically Window.fetch ported to Node-js).
|
||||
Basically what the app is doing is node-fetch is sending the request to the server then
|
||||
the app sends the response back to the server with the modifactions made to the attributes and elements.
|
||||
|
||||
When a attribute is rewritten, depending on the contents inside. It will turn:
|
||||
|
||||
`href="/assets/js/main.js"` into `href="/fetch/websiteURL/assets/js/main.js"`.
|
||||
|
||||
A porition of its rewriting is in client-side JS so `Element.setAttribute`, `window.fetch()`, XMLHttpRequest, and more are rewritten.
|
||||
|
||||
# Implementing your website in Alloyproxy
|
||||
|
||||
To implement your website into AlloyProxy. Upload all of your files into the `public` folder then your done. Avoid having the directory `alloy`
|
||||
Since that might mess up script injection stuff.
|
||||
|
||||
# Things not to do
|
||||
|
||||
We recommend NOT to delete the `alloy` folder. It contains script injection and error pages. And don't tamper with any rewriting that adds script injection since script injection makes websites such as Discord and Youtube work more properly.
|
||||
|
||||
# Extra information:
|
||||
|
||||
If your gonna have an external website redirect to this proxy. Then we recommend you have the value base64 encoded and redirected to `/alloy?url=` then value.
|
||||
|
||||
# Deploying to Heroku:
|
||||
|
||||
If your gonna be hosting this on something like Heroku. You need to make sure SSL mode is turned off so this will work.
|
||||
|
||||
# Known websites that work
|
||||
|
||||
- Google Search
|
||||
|
||||
- Discord
|
||||
|
||||
- LittleBigSnake
|
||||
|
||||
- Surviv.io
|
||||
|
||||
- Youtube
|
||||
|
||||
- Y8
|
||||
|
||||
- 1v1.LOL
|
||||
|
||||
- Old Reddit
|
||||
|
||||
and plenty more!
|
||||
|
||||
# Known issues that need to be fixed
|
||||
|
||||
- Better POST body parsing instead of using body-parser.
|
||||
|
||||
- Cookie header rewriting
|
||||
|
||||
# Updates to come in the future
|
||||
|
||||
- Full URL encoding / encryption mode
|
||||
|
||||
- Websocket proxing
|
88
alloy/assets/error.html
Normal file
88
alloy/assets/error.html
Normal file
|
@ -0,0 +1,88 @@
|
|||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
body {
|
||||
background-color: #222;
|
||||
font-family: "Roboto";
|
||||
color: #FFF;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
input {
|
||||
background-color: #111;
|
||||
color :#FFF;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
width: 300px;
|
||||
font-size: 19px;
|
||||
height: 45px;
|
||||
margin-bottom: 5px;
|
||||
font-family: 'Roboto';
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #3333cc;
|
||||
color :#FFF;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
width: 300px;
|
||||
font-size: 19px;
|
||||
height: 45px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
button:hover{
|
||||
cursor: pointer;
|
||||
background-color: #4d4dff;
|
||||
}
|
||||
|
||||
.container p {
|
||||
margin-bottom: 10px;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
|
||||
.top {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-bottom: #FFF solid 1px;
|
||||
}
|
||||
.top p {
|
||||
font-family: "Noto Sans JP";
|
||||
font-size: 30px;
|
||||
margin: 22px 22px;
|
||||
display: block
|
||||
}
|
||||
|
||||
#error {
|
||||
padding: 0px 5px;
|
||||
font-size: 22px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top">
|
||||
<p>AlloyProxy</p>
|
||||
</div>
|
||||
<p id="error">%ERROR%</p>
|
||||
</body>
|
||||
</html>
|
209
alloy/assets/inject.js
Normal file
209
alloy/assets/inject.js
Normal file
|
@ -0,0 +1,209 @@
|
|||
// Ajax Rewriting
|
||||
|
||||
let apData = document.getElementById('alloyData');
|
||||
let urlData = apData.getAttribute('data-alloyURL');
|
||||
|
||||
|
||||
function rewriteURL(url, encoding) {
|
||||
var websiteURL
|
||||
if (encoding == 'base64') {
|
||||
websiteURL = btoa(url.split('/').splice(0, 3).join('/'))
|
||||
} else {
|
||||
websiteURL = url.split('/').splice(0, 3).join('/')
|
||||
}
|
||||
const path = '/' + url.split('/').splice(3).join('/')
|
||||
var rewritten
|
||||
if (path == '/') {
|
||||
rewritten = '/fetch/' + websiteURL
|
||||
} else {
|
||||
rewritten = `/fetch/${websiteURL}${path}`
|
||||
}
|
||||
return rewritten
|
||||
}
|
||||
let ajaxRewrite = window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
|
||||
if (url.startsWith(`${window.location.protocol}//${window.location.hostname}`) && !url.startsWith(`${window.location.protocol}//${window.location.hostname}/fetch/`)) {
|
||||
url = `/fetch/${urlData}/` + url.split('/').splice(3).join('/')
|
||||
} else if (url.startsWith('http')) {
|
||||
const hostname = url.split('/').slice(0, 3).join('/')
|
||||
const path = url.split('/').slice(3).join('/')
|
||||
const encodedHost = btoa(hostname)
|
||||
const fullURL = encodedHost + '/' + path
|
||||
url = '/fetch/' + fullURL
|
||||
} else if (url.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + url)
|
||||
url = '/alloy/?url=' + encodedURL
|
||||
} else if (url.startsWith('/')) {
|
||||
if (url.startsWith('/fetch')) {
|
||||
url = url
|
||||
} else if (url.startsWith('/alloy')) {
|
||||
url = url
|
||||
} else {
|
||||
let apData = document.getElementById('alloyData');
|
||||
let urlData = apData.getAttribute('data-alloyURL');
|
||||
url = '/fetch/' + urlData + url
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ajaxRewrite.apply(this, arguments);
|
||||
}
|
||||
|
||||
let windowFetchRewrite = window.fetch;window.fetch = function(url) {
|
||||
if (url.startsWith(`https://${window.location.hostname}`)) {
|
||||
url = url
|
||||
} else if (url.startsWith('http')) {
|
||||
const hostname = url.split('/').slice(0, 3).join('/')
|
||||
const path = url.split('/').slice(3).join('/')
|
||||
const encodedHost = btoa(hostname)
|
||||
const fullURL = encodedHost + '/' + path
|
||||
url = '/fetch/' + fullURL
|
||||
} else if (url.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + url)
|
||||
url = '/alloy/?url=' + encodedURL
|
||||
} else if (url.startsWith('/')) {
|
||||
if (url.startsWith('/fetch')) {
|
||||
url = url
|
||||
} else if (url.startsWith('/alloy')) {
|
||||
url = url
|
||||
} else {
|
||||
let apData = document.getElementById('alloyData');
|
||||
let urlData = apData.getAttribute('data-alloyURL');
|
||||
url = '/fetch/' + urlData + url
|
||||
}
|
||||
}
|
||||
return windowFetchRewrite.apply(this, arguments);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Create Element rewriting
|
||||
var original = document.createElement;
|
||||
document.createElement = function (tag) {
|
||||
var element = original.call(document, tag);
|
||||
if (tag.toLowerCase() === 'script') {
|
||||
Object.defineProperty(element.__proto__, 'src', {
|
||||
set: function(newValue) {
|
||||
if (newValue.startsWith('/fetch/')) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith('/alloy/')) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith(`https://${window.location.hostname}`)) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('https://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('http://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('/')) {
|
||||
element.setAttribute('src', '/fetch/' + urlData + newValue)
|
||||
} else {
|
||||
element.setAttribute('src', newValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (tag.toLowerCase() === 'iframe') {
|
||||
Object.defineProperty(element.__proto__, 'src', {
|
||||
set: function(newValue) {
|
||||
if (newValue.startsWith('/fetch/')) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith('/alloy/')) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith(`https://${window.location.hostname}`)) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('https://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('http://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('/')) {
|
||||
element.setAttribute('src', '/fetch/' + urlData + newValue)
|
||||
|
||||
} else {
|
||||
element.setAttribute('src', newValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (tag.toLowerCase() === 'link') {
|
||||
Object.defineProperty(element.__proto__, 'href', {
|
||||
set: function(newValue) {
|
||||
if (newValue.startsWith('/fetch/')) {
|
||||
element.setAttribute('href', newValue)
|
||||
} else if (newValue.startsWith('/alloy/')) {
|
||||
element.setAttribute('href', newValue)
|
||||
} else if (newValue.startsWith(`https://${window.location.hostname}`)) {
|
||||
element.setAttribute('href', newValue)
|
||||
} else if (newValue.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + newValue)
|
||||
element.setAttribute('href', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('https://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('href', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('http://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('href', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('/')) {
|
||||
element.setAttribute('href', '/fetch/' + urlData + newValue)
|
||||
|
||||
} else {
|
||||
element.setAttribute('href', newValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
let setAttributeRewrite = window.Element.prototype.setAttribute;window.Element.prototype.setAttribute = function(name, value) {
|
||||
switch(name) {
|
||||
case 'src':
|
||||
if (value.startsWith('/fetch/')) {
|
||||
value = value
|
||||
} else if (value.startsWith('/alloy/')) {
|
||||
value = value
|
||||
} else if (value.startsWith('//')) {
|
||||
value = rewriteURL('http:' + value, 'base64')
|
||||
} else if (value.startsWith('/')) {
|
||||
value = rewriteURL(urlData + value)
|
||||
break;
|
||||
} else if (value.startsWith('https://') || value.startsWith('http://')) {
|
||||
value = rewriteURL(value, 'base64')
|
||||
} else {
|
||||
value = value
|
||||
}
|
||||
break;
|
||||
case 'href':
|
||||
if (value.startsWith('/fetch/')) {
|
||||
value = value
|
||||
} else if (value.startsWith('//')) {
|
||||
value = rewriteURL('http:' + value, 'base64')
|
||||
} else if (value.startsWith('/')) {
|
||||
value = rewriteURL(urlData + value)
|
||||
break;
|
||||
} else if (value.startsWith('https://') || value.startsWith('http://')) {
|
||||
value = rewriteURL(value, 'base64')
|
||||
} else {
|
||||
value = value
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return setAttributeRewrite.apply(this, arguments);
|
||||
}
|
||||
|
||||
var previousState = window.history.state;
|
||||
setInterval(function() {
|
||||
if (!window.location.pathname.startsWith(`/fetch/${urlData}/`)) {
|
||||
history.replaceState('', '', `/fetch/${urlData}/${window.location.href.split('/').splice(3).join('/')}`);
|
||||
}
|
||||
}, 0.1);
|
337
app.js
Normal file
337
app.js
Normal file
|
@ -0,0 +1,337 @@
|
|||
var https = require('https');
|
||||
var http = require('http');
|
||||
var fetch = require('node-fetch');
|
||||
var express = require('express');
|
||||
var fs = require('fs');
|
||||
var app = express();
|
||||
var cookieParser = require('cookie-parser');
|
||||
var session = require('express-session');
|
||||
|
||||
var config = JSON.parse(fs.readFileSync('config.json', 'utf-8')),
|
||||
httpsAgent = new https.Agent({
|
||||
rejectUnauthorized: false,
|
||||
keepAlive: true,
|
||||
}),
|
||||
httpAgent = new http.Agent({
|
||||
rejectUnauthorized: false,
|
||||
keepAlive: true,
|
||||
}),
|
||||
ssl = { key: fs.readFileSync('ssl/default.key', 'utf8'), cert: fs.readFileSync('ssl/default.crt', 'utf8') },
|
||||
server,
|
||||
port = process.env.PORT || config.port,
|
||||
ready = (() => {
|
||||
var a = 'http://', b = config.listenip;
|
||||
if (config.ssl) a = 'https://';
|
||||
if (b == '0.0.0.0' || b == '127.0.0.1') b = 'localhost';
|
||||
console.log('AlloyProxy is now running at', a + b + ':' + port);
|
||||
});
|
||||
|
||||
http.globalAgent.maxSockets = Infinity;
|
||||
https.globalAgent.maxSockets = Infinity;
|
||||
|
||||
if (config.ssl) server = https.createServer(ssl, app).listen(port, config.listenip, ready);
|
||||
else server = http.createServer(app).listen(port, config.listenip, ready);
|
||||
|
||||
app.use(cookieParser());
|
||||
app.use(session({
|
||||
secret: 'alloy',
|
||||
saveUninitialized: true,
|
||||
resave: true
|
||||
}));
|
||||
|
||||
app.use((req, res, next)=>{
|
||||
// nice bodyparser alternative that wont cough up errors
|
||||
|
||||
req.setEncoding('utf8');
|
||||
req.raw_body = ''
|
||||
req.body = new Object()
|
||||
|
||||
req.on('data', chunk=>{ req.raw_body += chunk });
|
||||
|
||||
req.on('end', ()=>{
|
||||
req.str_body = req.raw_body.toString('utf8');
|
||||
|
||||
try{
|
||||
var result = new Object();
|
||||
|
||||
req.str_body.split('&').forEach((pair)=>{
|
||||
pair = pair.split('=');
|
||||
req.body[pair[0]] = decodeURIComponent(pair[1] || '');
|
||||
});
|
||||
}catch(err){
|
||||
req.body = {}
|
||||
}
|
||||
|
||||
return next();
|
||||
});
|
||||
});
|
||||
|
||||
function base64Encode(data) {
|
||||
return new Buffer.from(data).toString('base64')
|
||||
}
|
||||
|
||||
// How to use: base64Decode('string') will return any input base64 decoded
|
||||
function base64Decode(data) {
|
||||
return new Buffer.from(data, 'base64').toString('ascii')
|
||||
}
|
||||
|
||||
// How to use: rewritingURL('https://example.org/assets/main.js') will rewrite any external URL. Output: aHR0cHM6Ly9leGFtcGxlLm9yZw==/assets/main.js
|
||||
function rewriteURL(dataURL, option) {
|
||||
var websiteURL
|
||||
var websitePath
|
||||
if (option == 'decode') {
|
||||
websiteURL = base64Decode(dataURL.split('/').splice(0, 1).join('/'))
|
||||
websitePath = '/' + dataURL.split('/').splice(1).join('/')
|
||||
} else {
|
||||
websiteURL = base64Encode(dataURL.split('/').splice(0, 3).join('/'))
|
||||
websitePath = '/' + dataURL.split('/').splice(3).join('/')
|
||||
}
|
||||
if (websitePath == '/') {
|
||||
return `${websiteURL}`
|
||||
} else return `${websiteURL}${websitePath}`
|
||||
}
|
||||
|
||||
// To be used with res.send() to send error. Example: res.send(error('404', 'No valid directory or file was found!'))
|
||||
function error(statusCode, info) {
|
||||
if (statusCode && info) {
|
||||
return fs.readFileSync('alloy/assets/error.html', 'utf8').toString().replace('%ERROR%', `Error ${statusCode}: ${info}`)
|
||||
}
|
||||
if (info && !statusCode) {
|
||||
return fs.readFileSync('alloy/assets/error.html', 'utf8').toString().replace('%ERROR%', `Error: ${info}`)
|
||||
}
|
||||
if (statusCode && !info) {
|
||||
return fs.readFileSync('alloy/assets/error.html', 'utf8').toString().replace('%ERROR%', `Error ${statusCode}`)
|
||||
}
|
||||
return fs.readFileSync('public/assets/error.html', 'utf8').toString().replace('%ERROR%', `An error has occurred!`)
|
||||
}
|
||||
|
||||
app.post('/createSession', async (req, res) => {
|
||||
if (req.body.url.startsWith('//')) {
|
||||
req.body.url = 'http:' + req.body.url;
|
||||
} else if (req.body.url.startsWith('https://') || req.body.url.startsWith('http://')) {
|
||||
req.body.url = req.body.url;
|
||||
} else {
|
||||
req.body.url = 'http://' + req.body.url;
|
||||
}
|
||||
if (req.body.rv) {
|
||||
req.session.rvURL = String(req.body.url).split('/').splice(0, 3).join('/')
|
||||
return res.redirect('/fetch/rv/' + String(req.body.url).split('/').splice(3).join('/'))
|
||||
} else {
|
||||
return res.redirect('/fetch/' + rewriteURL(String(req.body.url)))
|
||||
}
|
||||
})
|
||||
|
||||
var prefix = '/fetch';
|
||||
|
||||
app.use(prefix, async (req, res, next) => {
|
||||
var location = rewriteURL(req.url.slice(1), 'decode');
|
||||
if (req.url.startsWith('/rv') && !req.session.rvURL) {
|
||||
res.send(error('400', 'No valid session URL for reverse proxy mode was found!'))
|
||||
}
|
||||
if (req.url.startsWith('/rv') && req.session.rvURL) {
|
||||
location = req.session.rvURL + req.url.slice(3)
|
||||
}
|
||||
location = {
|
||||
href: location,
|
||||
hostname : location.split('/').splice(2).splice(0, 1).join('/'),
|
||||
origin : location.split('/').splice(0, 3).join('/'),
|
||||
origin_encoded : base64Encode(location.split('/').splice(0, 3).join('/')),
|
||||
path : '/' + location.split('/').splice(3).join('/'),
|
||||
protocol : location.split('\:').splice(0, 1).join(''),
|
||||
}
|
||||
var httpAgent = new http.Agent({
|
||||
keepAlive: true
|
||||
});
|
||||
var httpsAgent = new https.Agent({
|
||||
keepAlive: true
|
||||
});
|
||||
|
||||
var fetchHeaders = req.headers
|
||||
fetchHeaders['referer'] = location.href
|
||||
fetchHeaders['origin'] = location.origin
|
||||
fetchHeaders['host'] = location.hostname
|
||||
if (fetchHeaders['cookie']) {
|
||||
delete fetchHeaders['cookie']
|
||||
}
|
||||
var options = {
|
||||
method: req.method,
|
||||
headers: fetchHeaders,
|
||||
redirect: 'manual',
|
||||
agent: function(_parsedURL) {
|
||||
if (_parsedURL.protocol == 'http:') {
|
||||
return httpAgent;
|
||||
} else {
|
||||
return httpsAgent;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (req.method == 'POST') {
|
||||
// Have to do try catch for this POST data parser until we create our own one that won't have a syntax error sometimes.
|
||||
try {
|
||||
// str_body is a string containing the requests body
|
||||
options['body'] = req.str_body;
|
||||
}catch(err){
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (req.url.startsWith('/rv')) {
|
||||
location.origin_encoded = 'rv'
|
||||
}
|
||||
if (!req.url.startsWith(`/${location.origin_encoded}/`)) {
|
||||
try{
|
||||
return res.redirect(307,`/fetch/${location.origin_encoded}/`)
|
||||
}catch(err){
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (location.href == 'https://discord.com' || location.href == 'https://discord.com/new') {
|
||||
return res.redirect(307, `/fetch/${location.origin_encoded}/login`)
|
||||
}
|
||||
if (location.origin == 'https://www.reddit.com') {
|
||||
if (req.url.startsWith('/rv') && req.session.rvURL) {
|
||||
req.session.rvURL = 'https://old.reddit.com'
|
||||
return res.redirect(307, '/fetch/rv' + location.path)
|
||||
}
|
||||
return res.redirect(307, '/fetch/' + base64Encode('https://old.reddit.com') + location.path)
|
||||
}
|
||||
const response = await fetch(location.href, options).catch(err => res.send(error('404', `"${location.href}" was not found!`)));
|
||||
if(typeof response.buffer != 'function')return;
|
||||
var resbody = await response.buffer();
|
||||
var contentType = 'text/plain'
|
||||
|
||||
response.headers.forEach((e, i, a) => {
|
||||
if (i == 'content-type') contentType = e;
|
||||
});
|
||||
if (contentType == null || typeof contentType == 'undefined') ct = 'text/html';
|
||||
var serverHeaders = Object.fromEntries(
|
||||
Object.entries(JSON.parse(JSON.stringify(response.headers.raw())))
|
||||
.map(([key, val]) => [key, val[0]])
|
||||
);
|
||||
if (serverHeaders['location']) {
|
||||
if (req.url.startsWith('/rv') && req.session.rvURL) {
|
||||
req.session.rvURL = String(serverHeaders['location']).split('/').splice(0, 3).join('/')
|
||||
return res.redirect(307, '/fetch/rv/' + String(serverHeaders['location']).split('/').splice(3).join('/'))
|
||||
} else return res.redirect(307, '/fetch/' + rewriteURL(String(serverHeaders['location'])))
|
||||
}
|
||||
delete serverHeaders['content-encoding']
|
||||
delete serverHeaders['x-frame-options']
|
||||
delete serverHeaders['strict-transport-security']
|
||||
delete serverHeaders['content-security-policy']
|
||||
delete serverHeaders['location']
|
||||
res.status(response.status)
|
||||
res.set(serverHeaders)
|
||||
res.contentType(contentType)
|
||||
if (response.redirected == true) {
|
||||
if (req.url.startsWith('/rv') && req.session.rvURL) {
|
||||
req.session.rvURL = response.url.split('/').splice(0, 3).join('/')
|
||||
return res.redirect(307, '/fetch/rv/' + response.url.split('/').splice(3).join('/'))
|
||||
} else return res.redirect(307, '/fetch/' + rewriteURL(response.url))
|
||||
}
|
||||
if (contentType.startsWith('text/html')) {
|
||||
req.session.fetchURL = location.origin_encoded
|
||||
resbody = resbody.toString()
|
||||
.replace(/integrity="(.*?)"/gi, '')
|
||||
.replace(/nonce="(.*?)"/gi, '')
|
||||
.replace(/(href|src|poster|data|action)="\/\/(.*?)"/gi, `$1` + `="http://` + `$2` + `"`)
|
||||
.replace(/(href|src|poster|data|action)='\/\/(.*?)'/gi, `$1` + `='http://` + `$2` + `'`)
|
||||
.replace(/(href|src|poster|data|action)="\/(.*?)"/gi, `$1` + `="/fetch/${location.origin_encoded}/` + `$2` + `"`)
|
||||
.replace(/(href|src|poster|data|action)='\/(.*?)'/gi, `$1` + `='/fetch/${location.origin_encoded}/` + `$2` + `'`)
|
||||
.replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) {
|
||||
str = str.split(`'`).slice(1).slice(0, -1).join(``);
|
||||
return `'/fetch/${rewriteURL(str)}'`
|
||||
})
|
||||
.replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) {
|
||||
str = str.split(`"`).slice(1).slice(0, -1).join(``);
|
||||
return `"/fetch/${rewriteURL(str)}"`
|
||||
})
|
||||
.replace(/(window|document).location.href/gi, `"${location.href}"`)
|
||||
.replace(/(window|document).location.hostname/gi, `"${location.hostname}"`)
|
||||
.replace(/(window|document).location.pathname/gi, `"${location.path}"`)
|
||||
.replace(/location.href/gi, `"${location.href}"`)
|
||||
.replace(/location.hostname/gi, `"${location.hostname}"`)
|
||||
.replace(/location.pathname/gi, `"${location.path}"`)
|
||||
.replace(/<html(.*?)>/gi, '<html' + '$1' + '><script id="alloyData" data-alloyURL="' + location.origin_encoded + '"' + ' src="/alloy/assets/inject.js"></script>')
|
||||
|
||||
} else if (contentType.startsWith('text/css')) {
|
||||
resbody = resbody.toString()
|
||||
.replace(/url\("\/\/(.*?)"\)/gi, `url("http://` + `$1` + `")`)
|
||||
.replace(/url\('\/\/(.*?)'\)/gi, `url('http://` + `$1` + `')`)
|
||||
.replace(/url\(\/\/(.*?)\)/gi, `url(http://` + `$1` + `)`)
|
||||
.replace(/url\("\/(.*?)"\)/gi, `url("/fetch/${location.origin_encoded}/` + `$1` + `")`)
|
||||
.replace(/url\('\/(.*?)'\)/gi, `url('/fetch/${location.origin_encoded}/` + `$1` + `')`)
|
||||
.replace(/url\(\/(.*?)\)/gi, `url(/fetch/${location.origin_encoded}/` + `$1` + `)`)
|
||||
.replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) {
|
||||
str = str.split(`"`).slice(1).slice(0, -1).join(``);
|
||||
return `"/fetch/${rewriteURL(str)}"`
|
||||
})
|
||||
.replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) {
|
||||
str = str.split(`'`).slice(1).slice(0, -1).join(``);
|
||||
return `'/fetch/${rewriteURL(str)}'`
|
||||
})
|
||||
.replace(/\((https:\/\/|http:\/\/)(.*?)\)/gi, function(str) {
|
||||
str = str.split(`(`).slice(1).join(``).split(')').slice(0, -1).join('');
|
||||
return `(/fetch/${rewriteURL(str)})`
|
||||
})
|
||||
|
||||
} else if (contentType.startsWith('text/javascript') || contentType.startsWith('application/javascript')) {
|
||||
resbody = resbody.toString()
|
||||
.replace(/xhttp.open\("GET",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhttp.open("GET",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true')
|
||||
.replace(/xhttp.open\("POST",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhttp.open("POST",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true')
|
||||
.replace(/xhttp.open\("OPTIONS",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhttp.open("OPTIONS",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true')
|
||||
|
||||
.replace(/xhr.open\("GET",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhr.open("GET",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true')
|
||||
.replace(/xhr.open\("POST",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhr.open("POST",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true')
|
||||
.replace(/xhr.open\("OPTIONS",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhr.open("OPTIONS",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true')
|
||||
.replace(/ajax\("http:\/\/(.*?)"\)/gi, 'ajax("/alloy/url/http://' + '$1' + '")')
|
||||
.replace(/ajax\("https:\/\/(.*?)"\)/gi, 'ajax("/alloy/url/https://' + '$1' + '")')
|
||||
}
|
||||
res.send(resbody)
|
||||
})
|
||||
|
||||
app.use('/alloy/url/',function (req, res, next) {
|
||||
const mainurl = req.url.split('/').slice(1).join('/')
|
||||
const host = mainurl.split('/').slice(0, 3).join('/')
|
||||
const buff = new Buffer(host);
|
||||
const host64 = buff.toString('base64');
|
||||
const path = mainurl.split('/').slice(3).join('/')
|
||||
const fullURL = host64 + '/' + path
|
||||
res.redirect(307, '/fetch/' + fullURL)
|
||||
})
|
||||
|
||||
|
||||
app.use('/alloy/',function (req, res, next) {
|
||||
|
||||
if (req.query.url) {
|
||||
var clientInput = base64Decode(req.query.url)
|
||||
var fetchURL;
|
||||
if (clientInput.startsWith('//')) {
|
||||
fetchURL = rewriteURL('http:' + clientInput)
|
||||
} else if (clientInput.startsWith('http://') || clientInput.startsWith('https://')) {
|
||||
fetchURL = rewriteURL(clientInput)
|
||||
} else {
|
||||
fetchURL = rewriteURL('http://' + clientInput)
|
||||
}
|
||||
return res.redirect(307, '/fetch/' + fetchURL)
|
||||
}
|
||||
res.sendFile(__dirname + '/alloy' + req.url, function (err) {
|
||||
if (err) {
|
||||
if (req.session.fetchURL) {
|
||||
return res.redirect(307, '/fetch/' + req.session.fetchURL + req.url)
|
||||
} else return res.redirect(307, '/')
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
res.sendFile(__dirname + '/public' + req.url, function (err) {
|
||||
if (err) {
|
||||
if (req.session.fetchURL) {
|
||||
return res.redirect(307, '/fetch/' + req.session.fetchURL + req.url)
|
||||
} else return res.redirect(307, '/')
|
||||
}
|
||||
})
|
||||
|
||||
});
|
7
app.json
Normal file
7
app.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "Alloy Proxy",
|
||||
"description": "A node.js web proxy featuring URL encoding, and amazing compatablity!",
|
||||
"repository": "https://github.com/titaniumnetwork-dev/alloyproxy/",
|
||||
"logo": "https://avatars1.githubusercontent.com/u/47227492?s=200&v=4",
|
||||
"keywords": ["node", "proxy", "unblocker"]
|
||||
}
|
5
config.json
Normal file
5
config.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"listenip":"0.0.0.0",
|
||||
"port":8080,
|
||||
"ssl":false
|
||||
}
|
443
package-lock.json
generated
Normal file
443
package-lock.json
generated
Normal file
|
@ -0,0 +1,443 @@
|
|||
{
|
||||
"name": "alloyproxy",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"accepts": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
|
||||
"requires": {
|
||||
"mime-types": "~2.1.24",
|
||||
"negotiator": "0.6.2"
|
||||
}
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
||||
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
|
||||
"requires": {
|
||||
"bytes": "3.1.0",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"http-errors": "1.7.2",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "~2.3.0",
|
||||
"qs": "6.7.0",
|
||||
"raw-body": "2.4.0",
|
||||
"type-is": "~1.6.17"
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
|
||||
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.2"
|
||||
}
|
||||
},
|
||||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
|
||||
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
|
||||
},
|
||||
"cookie-parser": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz",
|
||||
"integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==",
|
||||
"requires": {
|
||||
"cookie": "0.4.0",
|
||||
"cookie-signature": "1.0.6"
|
||||
}
|
||||
},
|
||||
"cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
|
||||
},
|
||||
"destroy": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
|
||||
},
|
||||
"escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||
},
|
||||
"etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
|
||||
},
|
||||
"express": {
|
||||
"version": "4.17.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
|
||||
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
|
||||
"requires": {
|
||||
"accepts": "~1.3.7",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.19.0",
|
||||
"content-disposition": "0.5.3",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.4.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "~1.1.2",
|
||||
"fresh": "0.5.2",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "~2.3.0",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"proxy-addr": "~2.0.5",
|
||||
"qs": "6.7.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.1.2",
|
||||
"send": "0.17.1",
|
||||
"serve-static": "1.14.1",
|
||||
"setprototypeof": "1.1.1",
|
||||
"statuses": "~1.5.0",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "~1.1.2"
|
||||
}
|
||||
},
|
||||
"express-session": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.1.tgz",
|
||||
"integrity": "sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q==",
|
||||
"requires": {
|
||||
"cookie": "0.4.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~2.0.0",
|
||||
"on-headers": "~1.0.2",
|
||||
"parseurl": "~1.3.3",
|
||||
"safe-buffer": "5.2.0",
|
||||
"uid-safe": "~2.1.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
|
||||
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"finalhandler": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||
"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "~2.3.0",
|
||||
"parseurl": "~1.3.3",
|
||||
"statuses": "~1.5.0",
|
||||
"unpipe": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
|
||||
"integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA=="
|
||||
},
|
||||
"forwarded": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
|
||||
},
|
||||
"fresh": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
|
||||
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
|
||||
"requires": {
|
||||
"depd": "~1.1.2",
|
||||
"inherits": "2.0.3",
|
||||
"setprototypeof": "1.1.1",
|
||||
"statuses": ">= 1.5.0 < 2",
|
||||
"toidentifier": "1.0.0"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||
},
|
||||
"merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.27",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
|
||||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
|
||||
"requires": {
|
||||
"mime-db": "1.44.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
|
||||
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
|
||||
"requires": {
|
||||
"ee-first": "1.1.1"
|
||||
}
|
||||
},
|
||||
"on-headers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
|
||||
},
|
||||
"parse-raw-http": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse-raw-http/-/parse-raw-http-0.0.1.tgz",
|
||||
"integrity": "sha512-GndQvIQXviId7eHnc+fEcmtEjkj1tQ96EhNOplPwXA8L1jgOnrlx/xLmmOEew8Yj4ZoZpmoAh0IvypAaeMbILg=="
|
||||
},
|
||||
"parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||
},
|
||||
"proxy-addr": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
|
||||
"integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
|
||||
"requires": {
|
||||
"forwarded": "~0.1.2",
|
||||
"ipaddr.js": "1.9.1"
|
||||
}
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
||||
},
|
||||
"random-bytes": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
||||
"integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
|
||||
},
|
||||
"range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
|
||||
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
|
||||
"requires": {
|
||||
"bytes": "3.1.0",
|
||||
"http-errors": "1.7.2",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"send": {
|
||||
"version": "0.17.1",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
|
||||
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"destroy": "~1.0.4",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "~1.7.2",
|
||||
"mime": "1.6.0",
|
||||
"ms": "2.1.1",
|
||||
"on-finished": "~2.3.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"statuses": "~1.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve-static": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
|
||||
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
|
||||
"requires": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.17.1"
|
||||
}
|
||||
},
|
||||
"setprototypeof": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
|
||||
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
|
||||
},
|
||||
"toidentifier": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
||||
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||
"requires": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.24"
|
||||
}
|
||||
},
|
||||
"uid-safe": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
|
||||
"requires": {
|
||||
"random-bytes": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||
},
|
||||
"utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||
}
|
||||
}
|
||||
}
|
32
package.json
Normal file
32
package.json
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "alloyproxy",
|
||||
"version": "1.0.0",
|
||||
"description": "A powerful web proxy!",
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"test": "proxy",
|
||||
"start": "node app.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/titaniumnetwork-dev/alloyproxy.git"
|
||||
},
|
||||
"keywords": [
|
||||
"web-proxy"
|
||||
],
|
||||
"author": "titaniumnetwork-dev",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/titaniumnetwork-dev/alloyproxy/issues"
|
||||
},
|
||||
"homepage": "https://github.com/titaniumnetwork-dev/alloyproxy#readme",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"express": "^4.17.1",
|
||||
"express-session": "^1.17.1",
|
||||
"follow-redirects": "^1.13.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"parse-raw-http": "0.0.1"
|
||||
}
|
||||
}
|
674
public/LICENSE
Normal file
674
public/LICENSE
Normal file
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
120
public/a.html
Normal file
120
public/a.html
Normal file
|
@ -0,0 +1,120 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||
<title>Launch Meeting − Zoom</title>
|
||||
<meta name="description" content="Get past internet censorship today!
|
||||
|
||||
:D">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="assets/img/icon.png">
|
||||
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat+Alternates">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium+Web:400,600,700">
|
||||
<link rel="stylesheet" href="assets/fonts/ionicons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/Customizable-Background--Overlay.css">
|
||||
<link rel="stylesheet" href="assets/css/Footer-Dark.css">
|
||||
<link rel="stylesheet" href="assets/css/Header-Dark.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<div class="header-dark" style="background-color: rgb(0,0,0);background-image: url("assets/img/black.jpg");">
|
||||
<nav class="navbar navbar-dark navbar-expand-lg navigation-clean-search">
|
||||
<div class="container"><a class="navbar-brand" style="font-family: 'Montserrat Alternates', sans-serif;font-size: 21px;margin: 10px;font-style: normal;font-weight: bold;" href="/index.html">H<wbr>oly Unb<wbr>loc<wbr>ker</a>
|
||||
<div class="collapse navbar-collapse" id="navcol-1">
|
||||
<ul class="nav navbar-nav ml-auto">
|
||||
<li class="nav-item" role="presentation"><a class="nav-link active" href="/z.html">S<wbr>urf Fre<wbr>ely</a></li>
|
||||
<li class="nav-item" role="presentation"><a class="nav-link" href="g.html">Gam<wbr>es</a></li>
|
||||
<li class="nav-item" role="presentation"><a class="nav-link" href="/yt.html">YouTub<wbr>e</a></li>
|
||||
<li class="nav-item dropdown"><a class="dropdown-toggle nav-link" data-toggle="dropdown" aria-expanded="false" href="#">More</a>
|
||||
<div class="dropdown-menu" role="menu" style="background-color: rgb(33,30,30);font-family: 'Titillium Web', sans-serif;"><a class="dropdown-item" role="presentation" href="/k.html" style="color: rgb(255,255,255);">Krunker</a><a class="dropdown-item" role="presentation" href="/c.html" style="color: rgb(255,255,255);">Credits</a></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="particles-js" style="height: 500px;font-family: 'Montserrat Alternates', sans-serif;font-weight: bold;">
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: inherit;min-height: initial;width: 100%;position: absolute;left: 0;background-color: rgba(1,1,,0.63);">
|
||||
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
|
||||
<script>
|
||||
/* particlesJS.load(@dom-id, @path-json, @callback (optional)); */
|
||||
particlesJS.load('particles-js', 'particles.json', function() {
|
||||
console.log('particlesjs loaded.......');
|
||||
});
|
||||
</script>
|
||||
<div class="d-flex align-items-center order-12" style="height:200px;">
|
||||
<div class="container text-center justify-content-center align-items-center button" style="color: rgb(255,255,255);filter: blur(0px);background-color: #000000;">
|
||||
<form id="scontainer" method="POST" action="/createSession">
|
||||
<p style="font-size: 46px;">Al<wbr>loy Pr<wbr>oxy</p>
|
||||
<p style="font-family: 'Montserrat Alternates', sans-serif;">A fast, lightweight pr<wbr>o<wbr>xy developed by Ti<wbr>tan<wbr>ium Net<wbr>work.</p>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend"></div><input id="iurl" class="bg-white border rounded-0 border-warning shadow-lg form-control form-control-lg" type="text" name="url" value="https://google.com" style="width: 194px;font-family: 'Montserrat Alternates', sans-serif;">
|
||||
<div class="input-group-append"><button id="btn" class="btn btn-dark btn-lg bg-dark border rounded-0 border-warning shadow-lg select" type="submit" style="width: 78px;padding: 8px;margin: 0px;height: 48px;font-family: 'Montserrat Alternates', sans-serif;font-size: 16px;">A<wbr>lloy</button></div>
|
||||
</div>
|
||||
<div>
|
||||
<script>
|
||||
// function $(id) {
|
||||
// return document.getElementById(id);
|
||||
// };
|
||||
// $('scontainer').onsubmit = function() {
|
||||
// var url = $('url').value;
|
||||
// var det = document.domain;
|
||||
// var domain = det.replace('www.', '').split(/[/?#]/)[0];
|
||||
// window.location.href = "https://" + domain + "/alloy?url=" + url;
|
||||
// return false;
|
||||
// };
|
||||
// window.onload = function() {
|
||||
// $('url').focus();
|
||||
// }
|
||||
</script>
|
||||
</div>
|
||||
<p style="font-size: 20px;font-family: 'Montserrat Alternates', sans-serif;">More Information:<br></p>
|
||||
<p>Works on Discord (QR Code Only), Youtube (Might need to reload the page sometimes on first load), etc.<br>Many sites work with this. Explore!</p>
|
||||
<p>GitHub: <a class="text-danger" href="#"><strong><span style="text-decoration: underline;">https://github.com/titaniumnetwork-dev/alloyproxy</span></strong></a><br>Alloy Proxy created by SexyDuceDuce (a very epic person)
|
||||
:D
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-dark" style="background-color: rgb(0,0,0);">
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 item text">
|
||||
<h3>Holy Unblocker</h3>
|
||||
<p>Made by Students, For Students. </p>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 item">
|
||||
<h3>Services</h3>
|
||||
<ul>
|
||||
<li><a href="/a.html">Alloy</a></li>
|
||||
<li><a href="/b.html">Node</a></li>
|
||||
<li><a href="https://nodeclusters.com/">NodeClusters</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 item">
|
||||
<h3>About</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic">GitHub</a></li>
|
||||
<li><a href="c.html">Support</a></li>
|
||||
<li><a href="c.html">Credits</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col item social"><a href="https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic"><i class="icon ion-social-github-outline" style="font-family: 'Montserrat Alternates', sans-serif;"></i></a></div>
|
||||
</div>
|
||||
<p class="copyright">Holy Unblocker © 2020</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/header.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
6
public/assets/bootstrap/css/bootstrap.min.css
vendored
Normal file
6
public/assets/bootstrap/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
public/assets/bootstrap/js/bootstrap.min.js
vendored
Normal file
7
public/assets/bootstrap/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
85
public/assets/css/Button-Change-Text-on-Hover.css
Normal file
85
public/assets/css/Button-Change-Text-on-Hover.css
Normal file
|
@ -0,0 +1,85 @@
|
|||
.button {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin: 1em;
|
||||
padding: 10px 30px;
|
||||
border: 2px solid #ffffff;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
outline: none;
|
||||
color: #ffffff;
|
||||
background: transparent;
|
||||
font-family: 'Titillium Web', sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #ffffff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.button span {
|
||||
-webkit-transition: 0.4s;
|
||||
-moz-transition: 0.4s;
|
||||
-o-transition: 0.4s;
|
||||
transition: 0.4s;
|
||||
}
|
||||
|
||||
.button:before, .button:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
-webkit-transition: .4s;
|
||||
-moz-transition: .4s;
|
||||
-o-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.button:before {
|
||||
content: attr(data-hover);
|
||||
-webkit-transform: 0.4s;
|
||||
-moz-transform: 0.4s;
|
||||
-ms-transform: 0.4s;
|
||||
-o-transform: 0.4s;
|
||||
transform: 0.4s;
|
||||
}
|
||||
|
||||
.button:hover span, .button:active span {
|
||||
opacity: 0;
|
||||
-webkit-transform: 0.4s;
|
||||
-moz-transform: 0.4s;
|
||||
-ms-transform: 0.4s;
|
||||
-o-transform: 0.4s;
|
||||
transform: 0.4s;
|
||||
}
|
||||
|
||||
.button:hover:before, .button:active:after {
|
||||
opacity: 1;
|
||||
-webkit-transform: 0.4s;
|
||||
-moz-transform: 0.4s;
|
||||
-ms-transform: 0.4s;
|
||||
-o-transform: 0.4s;
|
||||
transform: 0.4s;
|
||||
-webkit-transition-delay: .4s;
|
||||
-moz-transition-delay: .4s;
|
||||
-o-transition-delay: .4s;
|
||||
transition-delay: .4s;
|
||||
}
|
||||
|
||||
.button:active:before {
|
||||
-webkit-transform: 0.4s;
|
||||
-moz-transform: 0.4s;
|
||||
-ms-transform: 0.4s;
|
||||
-o-transform: 0.4s;
|
||||
transform: 0.4s;
|
||||
-webkit-transition-delay: 0s;
|
||||
-moz-transition-delay: 0s;
|
||||
-o-transition-delay: 0s;
|
||||
transition-delay: 0s;
|
||||
}
|
||||
|
12
public/assets/css/Customizable-Background--Overlay.css
Normal file
12
public/assets/css/Customizable-Background--Overlay.css
Normal file
|
@ -0,0 +1,12 @@
|
|||
*, *:before, *:after {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
*, *:before, *:after {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
90
public/assets/css/Footer-Dark.css
Normal file
90
public/assets/css/Footer-Dark.css
Normal file
|
@ -0,0 +1,90 @@
|
|||
.footer-dark {
|
||||
padding: 50px 0;
|
||||
color: #f0f9ff;
|
||||
background-color: #282d32;
|
||||
}
|
||||
|
||||
.footer-dark h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 12px;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.footer-dark ul {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
line-height: 1.6;
|
||||
font-size: 14px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.footer-dark ul a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.footer-dark ul a:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@media (max-width:767px) {
|
||||
.footer-dark .item:not(.social) {
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-dark .item.text {
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
|
||||
@media (max-width:767px) {
|
||||
.footer-dark .item.text {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-dark .item.text p {
|
||||
opacity: 0.6;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.footer-dark .item.social {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width:991px) {
|
||||
.footer-dark .item.social {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-dark .item.social > a {
|
||||
font-size: 20px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 0 1px rgba(255,255,255,0.4);
|
||||
margin: 0 8px;
|
||||
color: #fff;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.footer-dark .item.social > a:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.footer-dark .copyright {
|
||||
text-align: center;
|
||||
padding-top: 24px;
|
||||
opacity: 0.3;
|
||||
font-size: 13px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
165
public/assets/css/Header-Dark.css
Normal file
165
public/assets/css/Header-Dark.css
Normal file
|
@ -0,0 +1,165 @@
|
|||
.header-dark {
|
||||
background: url(mountain_bg.jpg) #444;
|
||||
background-size: cover;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
@media (min-width:768px) {
|
||||
.header-dark {
|
||||
padding-bottom: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-dark .navbar {
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@media (min-width:768px) {
|
||||
.header-dark .navbar {
|
||||
padding-top: .75rem;
|
||||
padding-bottom: .75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-brand {
|
||||
font-weight: bold;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-brand:hover {
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-collapse span {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-collapse span .login {
|
||||
color: #d9d9d9;
|
||||
margin-right: .5rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-collapse span .login:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-toggler {
|
||||
border-color: #747474;
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-toggler:hover, .header-dark .navbar-toggler:focus {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-toggler {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-collapse, .header-dark .navbar .form-inline {
|
||||
border-color: #636363;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.header-dark .navbar.navbar .navbar-nav .nav-link {
|
||||
padding-left: 1.2rem;
|
||||
padding-right: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.header-dark .navbar.navbar-dark .navbar-nav .nav-link {
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
.header-dark .navbar.navbar-dark .navbar-nav .nav-link:focus, .header-dark .navbar.navbar-dark .navbar-nav .nav-link:hover {
|
||||
color: #fcfeff !important;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.header-dark .navbar .navbar-nav > li > .dropdown-menu {
|
||||
margin-top: -5px;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,.1);
|
||||
background-color: #fff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.header-dark .navbar .dropdown-menu .dropdown-item:focus, .header-dark .navbar .dropdown-menu .dropdown-item {
|
||||
line-height: 2;
|
||||
font-size: 14px;
|
||||
color: #37434d;
|
||||
}
|
||||
|
||||
.header-dark .navbar .dropdown-menu .dropdown-item:focus, .header-dark .navbar .dropdown-menu .drodown-item:hover {
|
||||
background: #ebeff1;
|
||||
}
|
||||
|
||||
.header-dark .navbar .action-button, .header-dark .navbar .action-button:active {
|
||||
background: #208f8f;
|
||||
border-radius: 20px;
|
||||
font-size: inherit;
|
||||
color: #fff;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
text-shadow: none;
|
||||
padding: .5rem .8rem;
|
||||
transition: background-color 0.25s;
|
||||
}
|
||||
|
||||
.header-dark .navbar .action-button:hover {
|
||||
background: #269d9d;
|
||||
}
|
||||
|
||||
.header-dark .navbar .form-inline label {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.header-dark .navbar .form-inline .search-field {
|
||||
display: inline-block;
|
||||
width: 80%;
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-radius: 0;
|
||||
color: #ccc;
|
||||
box-shadow: none;
|
||||
color: inherit;
|
||||
transition: border-bottom-color 0.3s;
|
||||
}
|
||||
|
||||
.header-dark .navbar .form-inline .search-field:focus {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.header-dark .hero {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
@media (min-width:768px) {
|
||||
.header-dark .hero {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-dark .hero h1 {
|
||||
color: #fff;
|
||||
font-family: 'Bitter', serif;
|
||||
font-size: 40px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
|
||||
@media (min-width:768px) {
|
||||
.header-dark .hero h1 {
|
||||
margin-bottom: 50px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.header-dark .hero .embed-responsive iframe {
|
||||
background-color: #666;
|
||||
}
|
||||
|
163
public/assets/css/Navigation-Clean.css
Normal file
163
public/assets/css/Navigation-Clean.css
Normal file
|
@ -0,0 +1,163 @@
|
|||
.navigation-clean {
|
||||
background: #fff;
|
||||
padding-top: .75rem;
|
||||
padding-bottom: .75rem;
|
||||
color: #333;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@media (min-width:768px) {
|
||||
.navigation-clean {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.navigation-clean .navbar-brand {
|
||||
font-weight: bold;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.navigation-clean .navbar-brand:hover {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .navbar-brand:hover {
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
.navigation-clean .navbar-brand img {
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.navigation-clean .navbar-toggler {
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
.navigation-clean .navbar-toggler:hover, .navigation-clean .navbar-toggler:focus {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .navbar-toggler {
|
||||
border-color: #555;
|
||||
}
|
||||
|
||||
.navigation-clean .navbar-toggler {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .navbar-toggler {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.navigation-clean .navbar-collapse, .navigation-clean .form-inline {
|
||||
border-top-color: #ddd;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .navbar-collapse, .navigation-clean.navbar-dark .form-inline {
|
||||
border-top-color: #333;
|
||||
}
|
||||
|
||||
.navigation-clean .navbar-nav > .active > a, .navigation-clean .navbar-nav > .show > a {
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-light .navbar-nav .nav-link.active, .navigation-clean.navbar-light .navbar-nav .nav-link.active:focus, .navigation-clean.navbar-light .navbar-nav .nav-link.active:hover {
|
||||
color: #8f8f8f;
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar .navbar-nav .nav-link {
|
||||
padding-left: 18px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-light .navbar-nav .nav-link {
|
||||
color: #465765;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-light .navbar-nav .nav-link:focus, .navigation-clean.navbar-light .navbar-nav .nav-link:hover {
|
||||
color: #37434d !important;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.navigation-clean .navbar-nav > li > .dropdown-menu {
|
||||
margin-top: -5px;
|
||||
box-shadow: none;
|
||||
background-color: #fff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
@media (min-width:768px) {
|
||||
.navigation-clean .navbar-nav .show .dropdown-menu {
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,.1);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width:767px) {
|
||||
.navigation-clean .navbar-nav .show .dropdown-menu .dropdown-item {
|
||||
color: #37434d;
|
||||
padding-top: .8rem;
|
||||
padding-bottom: .8rem;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.navigation-clean .dropdown-menu .dropdown-item:focus, .navigation-clean .dropdown-menu .dropdown-item {
|
||||
line-height: 2;
|
||||
color: #37434d;
|
||||
}
|
||||
|
||||
.navigation-clean .dropdown-menu .dropdown-item:focus, .navigation-clean .dropdown-menu .dropdown-item:hover {
|
||||
background: #eee;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark {
|
||||
background-color: #1f2021;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .navbar-nav a.active, .navigation-clean.navbar-dark .navbar-nav a.active:focus, .navigation-clean.navbar-dark .navbar-nav a.active:hover {
|
||||
color: #8f8f8f;
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .navbar-nav .nav-link {
|
||||
color: #dfe8ee;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .navbar-nav .nav-link:focus, .navigation-clean.navbar-dark .navbar-nav .nav-link:hover {
|
||||
color: #fff;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .navbar-nav > li > .dropdown-menu {
|
||||
background-color: #1f2021;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .dropdown-menu .dropdown-item:focus, .navigation-clean.navbar-dark .dropdown-menu .dropdown-item {
|
||||
color: #f2f5f8;
|
||||
}
|
||||
|
||||
.navigation-clean.navbar-dark .dropdown-menu .dropdown-item:focus, .navigation-clean.navbar-dark .dropdown-menu .dropdown-item:hover {
|
||||
background: #363739;
|
||||
}
|
||||
|
||||
@media (max-width:767px) {
|
||||
.navigation-clean.navbar-dark .navbar-nav .show .dropdown-menu .dropdown-item {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
7
public/assets/css/iframe.css
Normal file
7
public/assets/css/iframe.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
section {
|
||||
width: 100%;
|
||||
height: 238px;
|
||||
border: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
82
public/assets/css/style.css
Normal file
82
public/assets/css/style.css
Normal file
|
@ -0,0 +1,82 @@
|
|||
.gembed {
|
||||
width: 80%;
|
||||
height: 800%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.fbody {
|
||||
background-color: black;
|
||||
color: rgb(0, 0, 0);
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.glink {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font: 18px;
|
||||
border: 1px solid rgb(255, 166, 0);
|
||||
margin-top: -1px;
|
||||
background-color: #000000;
|
||||
padding: 12px;
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
.glink:hover {
|
||||
background-color: rgb(0, 0, 0);
|
||||
text-shadow: 0 0 5px rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
#gsearchbar {
|
||||
outline: none;
|
||||
width: 374px;
|
||||
top: 12px;
|
||||
font-size: 16px;
|
||||
border: 1px solid rgba(255, 115, 0, 0.3);
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
#gsearchbar:focus {
|
||||
background-color: rgb(29, 27, 27);
|
||||
box-shadow: inset 0 0 5px 1px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.box {
|
||||
margin: auto;
|
||||
background-color: wblack;
|
||||
padding: 10px 10px 15px 10px;
|
||||
width: 420px;
|
||||
height: 540px;
|
||||
}
|
||||
|
||||
#glist {
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
width: 400px;
|
||||
height: 520px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#glist h2 {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font: 18px;
|
||||
border: 1px solid #060606;
|
||||
margin: -1px 0 0 0;
|
||||
background-color: #060606;
|
||||
padding: 12px;
|
||||
font-weight: bold;
|
||||
user-select: none;
|
||||
}
|
BIN
public/assets/fonts/ionicons.eot
Normal file
BIN
public/assets/fonts/ionicons.eot
Normal file
Binary file not shown.
11
public/assets/fonts/ionicons.min.css
vendored
Normal file
11
public/assets/fonts/ionicons.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2230
public/assets/fonts/ionicons.svg
Normal file
2230
public/assets/fonts/ionicons.svg
Normal file
File diff suppressed because it is too large
Load diff
After Width: | Height: | Size: 326 KiB |
BIN
public/assets/fonts/ionicons.ttf
Normal file
BIN
public/assets/fonts/ionicons.ttf
Normal file
Binary file not shown.
BIN
public/assets/fonts/ionicons.woff
Normal file
BIN
public/assets/fonts/ionicons.woff
Normal file
Binary file not shown.
BIN
public/assets/img/black.jpg
Normal file
BIN
public/assets/img/black.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 131 KiB |
BIN
public/assets/img/icon.png
Normal file
BIN
public/assets/img/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
211
public/assets/inject.js
Normal file
211
public/assets/inject.js
Normal file
|
@ -0,0 +1,211 @@
|
|||
// Ajax Rewriting
|
||||
|
||||
let apData = document.getElementById('alloyData');
|
||||
let urlData = apData.getAttribute('data-alloyURL');
|
||||
|
||||
|
||||
function rewriteURL(url, encoding) {
|
||||
var websiteURL
|
||||
if (encoding == 'base64') {
|
||||
websiteURL = btoa(url.split('/').splice(0, 3).join('/'))
|
||||
} else {
|
||||
websiteURL = url.split('/').splice(0, 3).join('/')
|
||||
}
|
||||
const path = '/' + url.split('/').splice(3).join('/')
|
||||
var rewritten
|
||||
if (path == '/') {
|
||||
rewritten = '/fetch/' + websiteURL
|
||||
} else {
|
||||
rewritten = `/fetch/${websiteURL}${path}`
|
||||
}
|
||||
return rewritten
|
||||
}
|
||||
let ajaxRewrite = window.XMLHttpRequest.prototype.open;
|
||||
window.XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
|
||||
if (url.startsWith(`${window.location.protocol}//${window.location.hostname}`) && !url.startsWith(`${window.location.protocol}//${window.location.hostname}/fetch/`)) {
|
||||
url = `/fetch/${urlData}/` + url.split('/').splice(3).join('/')
|
||||
} else if (url.startsWith('http')) {
|
||||
const hostname = url.split('/').slice(0, 3).join('/')
|
||||
const path = url.split('/').slice(3).join('/')
|
||||
const encodedHost = btoa(hostname)
|
||||
const fullURL = encodedHost + '/' + path
|
||||
url = '/fetch/' + fullURL
|
||||
} else if (url.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + url)
|
||||
url = '/alloy/?url=' + encodedURL
|
||||
} else if (url.startsWith('/')) {
|
||||
if (url.startsWith('/fetch')) {
|
||||
url = url
|
||||
} else if (url.startsWith('/alloy')) {
|
||||
url = url
|
||||
} else {
|
||||
let apData = document.getElementById('alloyData');
|
||||
let urlData = apData.getAttribute('data-alloyURL');
|
||||
url = '/fetch/' + urlData + url
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ajaxRewrite.apply(this, arguments);
|
||||
}
|
||||
|
||||
let windowFetchRewrite = window.fetch;
|
||||
window.fetch = function(url) {
|
||||
if (url.startsWith(`https://${window.location.hostname}`)) {
|
||||
url = url
|
||||
} else if (url.startsWith('http')) {
|
||||
const hostname = url.split('/').slice(0, 3).join('/')
|
||||
const path = url.split('/').slice(3).join('/')
|
||||
const encodedHost = btoa(hostname)
|
||||
const fullURL = encodedHost + '/' + path
|
||||
url = '/fetch/' + fullURL
|
||||
} else if (url.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + url)
|
||||
url = '/alloy/?url=' + encodedURL
|
||||
} else if (url.startsWith('/')) {
|
||||
if (url.startsWith('/fetch')) {
|
||||
url = url
|
||||
} else if (url.startsWith('/alloy')) {
|
||||
url = url
|
||||
} else {
|
||||
let apData = document.getElementById('alloyData');
|
||||
let urlData = apData.getAttribute('data-alloyURL');
|
||||
url = '/fetch/' + urlData + url
|
||||
}
|
||||
}
|
||||
return windowFetchRewrite.apply(this, arguments);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Create Element rewriting
|
||||
var original = document.createElement;
|
||||
document.createElement = function(tag) {
|
||||
var element = original.call(document, tag);
|
||||
if (tag.toLowerCase() === 'script') {
|
||||
Object.defineProperty(element.__proto__, 'src', {
|
||||
set: function(newValue) {
|
||||
if (newValue.startsWith('/fetch/')) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith('/alloy/')) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith(`https://${window.location.hostname}`)) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('https://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('http://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('/')) {
|
||||
element.setAttribute('src', '/fetch/' + urlData + newValue)
|
||||
} else {
|
||||
element.setAttribute('src', newValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (tag.toLowerCase() === 'iframe') {
|
||||
Object.defineProperty(element.__proto__, 'src', {
|
||||
set: function(newValue) {
|
||||
if (newValue.startsWith('/fetch/')) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith('/alloy/')) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith(`https://${window.location.hostname}`)) {
|
||||
element.setAttribute('src', newValue)
|
||||
} else if (newValue.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('https://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('http://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('src', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('/')) {
|
||||
element.setAttribute('src', '/fetch/' + urlData + newValue)
|
||||
|
||||
} else {
|
||||
element.setAttribute('src', newValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (tag.toLowerCase() === 'link') {
|
||||
Object.defineProperty(element.__proto__, 'href', {
|
||||
set: function(newValue) {
|
||||
if (newValue.startsWith('/fetch/')) {
|
||||
element.setAttribute('href', newValue)
|
||||
} else if (newValue.startsWith('/alloy/')) {
|
||||
element.setAttribute('href', newValue)
|
||||
} else if (newValue.startsWith(`https://${window.location.hostname}`)) {
|
||||
element.setAttribute('href', newValue)
|
||||
} else if (newValue.startsWith('//')) {
|
||||
const encodedURL = btoa('http:' + newValue)
|
||||
element.setAttribute('href', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('https://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('href', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('http://')) {
|
||||
const encodedURL = btoa(newValue)
|
||||
element.setAttribute('href', '/alloy/?url=' + encodedURL)
|
||||
} else if (newValue.startsWith('/')) {
|
||||
element.setAttribute('href', '/fetch/' + urlData + newValue)
|
||||
|
||||
} else {
|
||||
element.setAttribute('href', newValue)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
let setAttributeRewrite = window.Element.prototype.setAttribute;
|
||||
window.Element.prototype.setAttribute = function(name, value) {
|
||||
switch (name) {
|
||||
case 'src':
|
||||
if (value.startsWith('/fetch/')) {
|
||||
value = value
|
||||
} else if (value.startsWith('/alloy/')) {
|
||||
value = value
|
||||
} else if (value.startsWith('//')) {
|
||||
value = rewriteURL('http:' + value, 'base64')
|
||||
} else if (value.startsWith('/')) {
|
||||
value = rewriteURL(urlData + value)
|
||||
break;
|
||||
} else if (value.startsWith('https://') || value.startsWith('http://')) {
|
||||
value = rewriteURL(value, 'base64')
|
||||
} else {
|
||||
value = value
|
||||
}
|
||||
break;
|
||||
case 'href':
|
||||
if (value.startsWith('/fetch/')) {
|
||||
value = value
|
||||
} else if (value.startsWith('//')) {
|
||||
value = rewriteURL('http:' + value, 'base64')
|
||||
} else if (value.startsWith('/')) {
|
||||
value = rewriteURL(urlData + value)
|
||||
break;
|
||||
} else if (value.startsWith('https://') || value.startsWith('http://')) {
|
||||
value = rewriteURL(value, 'base64')
|
||||
} else {
|
||||
value = value
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return setAttributeRewrite.apply(this, arguments);
|
||||
}
|
||||
|
||||
var previousState = window.history.state;
|
||||
setInterval(function() {
|
||||
if (!window.location.pathname.startsWith(`/fetch/${urlData}/`)) {
|
||||
history.replaceState('', '', `/fetch/${urlData}/${window.location.href.split('/').splice(3).join('/')}`);
|
||||
}
|
||||
}, 0.1);
|
140
public/assets/js/header.js
Normal file
140
public/assets/js/header.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
var date = new Date();
|
||||
date.setMonth(date.getMonth() + 12);
|
||||
date = date.toUTCString();
|
||||
|
||||
function randInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
var titles = [
|
||||
"‏‎",
|
||||
"Classes",
|
||||
"My Drive - Google Drive",
|
||||
"Google",
|
||||
"Home | Schoology",
|
||||
"My Meetings - Zoom"
|
||||
]
|
||||
|
||||
var icons = [
|
||||
"./img/blank.png",
|
||||
"https://ssl.gstatic.com/classroom/favicon.png",
|
||||
"https://ssl.gstatic.com/docs/doclist/images/infinite_arrow_favicon_5.ico",
|
||||
"https://www.google.com/favicon.ico",
|
||||
"https://asset-cdn.schoology.com/sites/all/themes/schoology_theme/favicon.ico",
|
||||
"https://d24cgw3uvb9a9h.cloudfront.net/zoom.ico"
|
||||
]
|
||||
|
||||
var psel, prss;
|
||||
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
psel = document.getElementById('psel');
|
||||
setPreferences();
|
||||
for (var i = 0; i < titles.length; i++) {
|
||||
if (i == 0) {
|
||||
psel.innerHTML += '<img title="(Blank)" src="./img/x.png">'
|
||||
} else {
|
||||
psel.innerHTML += '<img title="' + titles[i] + '" src="' + icons[i] + '">';
|
||||
}
|
||||
}
|
||||
document.getElementById('titleform').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
setTitle(this.firstChild.value);
|
||||
}, false);
|
||||
|
||||
document.getElementById('iconform').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
setIcon(this.firstChild.value);
|
||||
}, false);
|
||||
|
||||
document.getElementById('atch').addEventListener('click', autoChange, false);
|
||||
|
||||
psel.addEventListener('click', function(e) {
|
||||
prss = Array.from(psel.children).indexOf(e.target);
|
||||
if (prss != -1) {
|
||||
setTitle(titles[prss]);
|
||||
setIcon(icons[prss]);
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.getElementById('cwbox').addEventListener('click', function(e) {
|
||||
if (this.checked) {
|
||||
window.onbeforeunload = function(e) {
|
||||
var message = 'Oopsie poopsie'
|
||||
e.returnValue = message;
|
||||
return message;
|
||||
};
|
||||
} else {
|
||||
window.onbeforeunload = function() {};
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.getElementById('fullscreen').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
document.getElementById('theframe').requestFullscreen()
|
||||
return false;
|
||||
}, false);
|
||||
}, false);
|
||||
|
||||
function setPreferences() {
|
||||
if (readCookie('lemonTitle') != 'undefined') {
|
||||
pageTitle(readCookie('lemonTitle'));
|
||||
}
|
||||
if (readCookie('lemonIcon') != 'undefined') {
|
||||
pageIcon(readCookie('lemonIcon'));
|
||||
}
|
||||
}
|
||||
|
||||
function setCookie(name, value) {
|
||||
document.cookie = name + '=' + encodeURIComponent(value) + '; expires=' + date + '; ';
|
||||
}
|
||||
|
||||
function readCookie(name) {
|
||||
var cookie = document.cookie.split('; ');
|
||||
var cookies = {};
|
||||
for (var i = 0; i < cookie.length; i++) {
|
||||
var cur = cookie[i].split('=');
|
||||
cookies[cur[0]] = cur[1];
|
||||
}
|
||||
return decodeURIComponent(cookies[name]);
|
||||
}
|
||||
|
||||
function setTitle(value) {
|
||||
pageTitle(value);
|
||||
setCookie('lemonTitle', value);
|
||||
}
|
||||
|
||||
function setIcon(value) {
|
||||
pageIcon(value);
|
||||
setCookie('lemonIcon', value);
|
||||
}
|
||||
|
||||
function pageTitle(value) {
|
||||
document.getElementsByTagName('title')[0].innerHTML = value;
|
||||
try {
|
||||
parent.document.getElementsByTagName('title')[0].innerHTML = value;
|
||||
} catch (e) { console.log(e); }
|
||||
}
|
||||
|
||||
function pageIcon(value) {
|
||||
var link = document.querySelector("link[rel*='icon']") || document.createElement('link');
|
||||
link.rel = 'icon';
|
||||
link.href = value;
|
||||
document.getElementsByTagName('head')[0].appendChild(link);
|
||||
try {
|
||||
var link = parent.document.querySelector("link[rel*='icon']") || document.createElement('link');
|
||||
link.rel = 'icon';
|
||||
link.href = value;
|
||||
parent.document.getElementsByTagName('head')[0].appendChild(link);
|
||||
} catch (e) { console.log(e); }
|
||||
}
|
||||
|
||||
function autoChange() {
|
||||
if (document.getElementById('atch').checked) {
|
||||
var atci = randInt(1, 5);
|
||||
pageTitle(titles[atci]);
|
||||
pageIcon(icons[atci]);
|
||||
setTimeout(autoChange, randInt(10000, 60000));
|
||||
} else {
|
||||
setPreferences();
|
||||
}
|
||||
}
|
2
public/assets/js/jquery.min.js
vendored
Normal file
2
public/assets/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/assets/js/magic.js
Normal file
1
public/assets/js/magic.js
Normal file
|
@ -0,0 +1 @@
|
|||
//window.history.replaceState('', '', '/');
|
111
public/assets/js/surf.js
Normal file
111
public/assets/js/surf.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
function redir(type) {
|
||||
if (type == "cd") {
|
||||
var burl = btoa(document.getElementById('url').value);
|
||||
if (burl == "") {
|
||||
document.getElementById("empty").setAttribute("style", "display:inline");
|
||||
} else {
|
||||
document.getElementById("special").setAttribute("src", "./algebra/equation.php?cdURL=" + burl);
|
||||
document.getElementById("magic").setAttribute("style", "display:block");
|
||||
document.getElementById("empty").setAttribute("style", "display:none");
|
||||
}
|
||||
} else if (type == "php") {
|
||||
var burl = document.getElementById('url').value;
|
||||
if (burl == "") {
|
||||
document.getElementById("empty").setAttribute("style", "display:inline");
|
||||
} else {
|
||||
document.getElementById("special").setAttribute("src", "/sci/?prou=" + burl);
|
||||
document.getElementById("magic").setAttribute("style", "display:block");
|
||||
document.getElementById("empty").setAttribute("style", "display:none");
|
||||
document.cookie = 'option=pm; expires=' + (Date.now() + 259200) + '; sameSite=lax; domain=.' + purl + '; path=/; secure;';
|
||||
}
|
||||
} else if (type == "via") {
|
||||
var burl = document.getElementById('url').value;
|
||||
if (burl == "") {
|
||||
document.getElementById("empty").setAttribute("style", "display:inline");
|
||||
} else {
|
||||
document.getElementById("special").setAttribute("src", "https://c." + location.hostname + '/' + burl);
|
||||
document.getElementById("magic").setAttribute("style", "display:block");
|
||||
document.getElementById("empty").setAttribute("style", "display:none");
|
||||
document.cookie = 'oldsmobile=Y; expires=' + (Date.now() + 259200) + '; sameSite=lax; domain=.' + purl + '; path=/; secure;';
|
||||
|
||||
}
|
||||
} else if (type == "pm") {
|
||||
var burl = document.getElementById('url').value;
|
||||
if (burl == "") {
|
||||
document.getElementById("empty").setAttribute("style", "display:inline");
|
||||
} else {
|
||||
document.getElementById("special").setAttribute("src", "https://cdn." + location.hostname + '/' + burl);
|
||||
document.getElementById("magic").setAttribute("style", "display:block");
|
||||
document.getElementById("empty").setAttribute("style", "display:none");
|
||||
document.cookie = 'opt=pm; expires=' + (Date.now() + 259200) + '; sameSite=lax; domain=.' + purl + '; path=/; secure;';
|
||||
}
|
||||
} else if (type == "nc") {
|
||||
var burl = document.getElementById('url').value;
|
||||
if (burl == "") {
|
||||
document.getElementById("empty").setAttribute("style", "display:inline");
|
||||
} else {
|
||||
const origin = btoa(burl)
|
||||
document.getElementById("special").setAttribute("src", "https://cdn." + location.hostname + '/alloy?url=' + origin);
|
||||
document.getElementById("magic").setAttribute("style", "display:block");
|
||||
document.getElementById("empty").setAttribute("style", "display:none");
|
||||
document.cookie = 'opt=ap; expires=' + (Date.now() + 259200) + '; sameSite=lax; domain=.' + purl + '; path=/; secure;';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var host = location.hostname.split('.');
|
||||
var purl = location.hostname;
|
||||
if (host.length == 3) {
|
||||
purl = `${host[1]}.${host[2]}`;
|
||||
}
|
||||
Array.from(document.getElementsByTagName('button')).forEach(e => {
|
||||
e.addEventListener('click', () => {
|
||||
document.cookie = 'oldsmobile=owo; max-age=259200; sameSite=lax; domain=' + purl + '; path=/; secure;';
|
||||
});
|
||||
});
|
||||
|
||||
function invalid() {
|
||||
document.getElementById("invalid").setAttribute("style", "display:inline");
|
||||
}
|
||||
|
||||
|
||||
|
||||
function pm_select() {
|
||||
document.getElementsByClassName("material-icons")[0].setAttribute("onclick", "redir('pm')");
|
||||
document.getElementById("pm-info").setAttribute("style", "display:inline");
|
||||
document.getElementById("via-info").setAttribute("style", "display:none");
|
||||
document.getElementById("php-info").setAttribute("style", "display:none");
|
||||
document.getElementById("nc-info").setAttribute("style", "display:none");
|
||||
document.getElementById("invalid").setAttribute("style", "display:none");
|
||||
|
||||
|
||||
}
|
||||
|
||||
function via_select() {
|
||||
document.getElementsByClassName("material-icons")[0].setAttribute("onclick", "redir('via')");
|
||||
document.getElementById("pm-info").setAttribute("style", "display:none");
|
||||
document.getElementById("via-info").setAttribute("style", "display:inline");
|
||||
document.getElementById("php-info").setAttribute("style", "display:none");
|
||||
document.getElementById("nc-info").setAttribute("style", "display:none");
|
||||
document.getElementById("invalid").setAttribute("style", "display:none");
|
||||
|
||||
}
|
||||
|
||||
function nc_select() {
|
||||
document.getElementsByClassName("material-icons")[0].setAttribute("onclick", "redir('nc')");
|
||||
document.getElementById("pm-info").setAttribute("style", "display:none");
|
||||
document.getElementById("via-info").setAttribute("style", "display:none");
|
||||
document.getElementById("php-info").setAttribute("style", "display:none");
|
||||
document.getElementById("nc-info").setAttribute("style", "display:inline");
|
||||
document.getElementById("invalid").setAttribute("style", "display:none");
|
||||
|
||||
}
|
||||
|
||||
function php_select() {
|
||||
document.getElementsByClassName("material-icons")[0].setAttribute("onclick", "redir('php')");
|
||||
document.getElementById("pm-info").setAttribute("style", "display:none");
|
||||
document.getElementById("via-info").setAttribute("style", "display:none");
|
||||
document.getElementById("php-info").setAttribute("style", "display:inline");
|
||||
document.getElementById("nc-info").setAttribute("style", "display:none");
|
||||
document.getElementById("invalid").setAttribute("style", "display:none");
|
||||
}
|
110
public/assets/particles.json
Normal file
110
public/assets/particles.json
Normal file
|
@ -0,0 +1,110 @@
|
|||
{
|
||||
"particles": {
|
||||
"number": {
|
||||
"value": 240,
|
||||
"density": {
|
||||
"enable": true,
|
||||
"value_area": 1250.177108423694
|
||||
}
|
||||
},
|
||||
"color": {
|
||||
"value": "#ffffff"
|
||||
},
|
||||
"shape": {
|
||||
"type": "circle",
|
||||
"stroke": {
|
||||
"width": 2,
|
||||
"color": "#000000"
|
||||
},
|
||||
"polygon": {
|
||||
"nb_sides": 7
|
||||
},
|
||||
"image": {
|
||||
"src": "img/github.svg",
|
||||
"width": 100,
|
||||
"height": 100
|
||||
}
|
||||
},
|
||||
"opacity": {
|
||||
"value": 0.5,
|
||||
"random": false,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 1,
|
||||
"opacity_min": 0.1,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"value": 3,
|
||||
"random": true,
|
||||
"anim": {
|
||||
"enable": false,
|
||||
"speed": 40,
|
||||
"size_min": 0.1,
|
||||
"sync": false
|
||||
}
|
||||
},
|
||||
"line_linked": {
|
||||
"enable": true,
|
||||
"distance": 183.3593092354751,
|
||||
"color": "#ffffff",
|
||||
"opacity": 0.4,
|
||||
"width": 1
|
||||
},
|
||||
"move": {
|
||||
"enable": true,
|
||||
"speed": 6,
|
||||
"direction": "none",
|
||||
"random": false,
|
||||
"straight": false,
|
||||
"out_mode": "out",
|
||||
"bounce": false,
|
||||
"attract": {
|
||||
"enable": false,
|
||||
"rotateX": 600,
|
||||
"rotateY": 1200
|
||||
}
|
||||
}
|
||||
},
|
||||
"interactivity": {
|
||||
"detect_on": "canvas",
|
||||
"events": {
|
||||
"onhover": {
|
||||
"enable": false,
|
||||
"mode": "repulse"
|
||||
},
|
||||
"onclick": {
|
||||
"enable": true,
|
||||
"mode": "push"
|
||||
},
|
||||
"resize": true
|
||||
},
|
||||
"modes": {
|
||||
"grab": {
|
||||
"distance": 400,
|
||||
"line_linked": {
|
||||
"opacity": 1
|
||||
}
|
||||
},
|
||||
"bubble": {
|
||||
"distance": 400,
|
||||
"size": 40,
|
||||
"duration": 2,
|
||||
"opacity": 8,
|
||||
"speed": 3
|
||||
},
|
||||
"repulse": {
|
||||
"distance": 200,
|
||||
"duration": 0.4
|
||||
},
|
||||
"push": {
|
||||
"particles_nb": 4
|
||||
},
|
||||
"remove": {
|
||||
"particles_nb": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"retina_detect": true
|
||||
}
|
143
public/b.html
Normal file
143
public/b.html
Normal file
|
@ -0,0 +1,143 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||
<title>Launch Meeting − Zoom</title>
|
||||
<meta name="description" content="Get past internet censorship today!
|
||||
|
||||
:D">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="assets/img/icon.png">
|
||||
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat+Alternates">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium+Web:400,600,700">
|
||||
<link rel="stylesheet" href="assets/fonts/ionicons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/Customizable-Background--Overlay.css">
|
||||
<link rel="stylesheet" href="assets/css/Footer-Dark.css">
|
||||
<link rel="stylesheet" href="assets/css/Header-Dark.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<div class="header-dark" style="background-color: rgb(0,0,0);background-image: url("assets/img/black.jpg");">
|
||||
<nav class="navbar navbar-dark navbar-expand-lg navigation-clean-search">
|
||||
<div class="container"><a class="navbar-brand" style="font-family: 'Montserrat Alternates', sans-serif;font-size: 21px;margin: 10px;font-style: normal;font-weight: bold;" href="/index.html">Holy Unblocker</a>
|
||||
<div class="collapse navbar-collapse" id="navcol-1">
|
||||
<ul class="nav navbar-nav ml-auto">
|
||||
<li class="nav-item" role="presentation"><a class="nav-link active" href="/z.html">S<wbr>urf Fre<wbr>ely</a></li>
|
||||
<li class="nav-item" role="presentation"><a class="nav-link" href="g.html">Ga<wbr>mes</a></li>
|
||||
<li class="nav-item" role="presentation"><a class="nav-link" href="/yt.html">YouTube</a></li>
|
||||
<li class="nav-item dropdown"><a class="dropdown-toggle nav-link" data-toggle="dropdown" aria-expanded="false" href="#">More</a>
|
||||
<div class="dropdown-menu" role="menu" style="background-color: rgb(33,30,30);font-family: 'Titillium Web', sans-serif;"><a class="dropdown-item" role="presentation" href="/k.html" style="color: rgb(255,255,255);">Krunker</a><a class="dropdown-item" role="presentation" href="/c.html" style="color: rgb(255,255,255);">Credits</a></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="particles-js" style="height: 500px;font-family: 'Montserrat Alternates', sans-serif;font-weight: bold;">
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: inherit;min-height: initial;width: 100%;position: absolute;left: 0;background-color: rgba(1,1,,0.63);">
|
||||
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
|
||||
<script>
|
||||
/* particlesJS.load(@dom-id, @path-json, @callback (optional)); */
|
||||
particlesJS.load('particles-js', 'particles.json', function() {
|
||||
console.log('particlesjs loaded.......');
|
||||
});
|
||||
</script>
|
||||
<div class="d-flex align-items-center order-12" style="height:200px;">
|
||||
<div class="container text-center justify-content-center align-items-center button" style="color: rgb(255,255,255);filter: blur(0px);background-color: #000000;">
|
||||
<form id="unblocker-form">
|
||||
<p style="font-size: 46px;">N<wbr>ode Unbl<wbr>ocker</p>
|
||||
<p style="font-family: 'Montserrat Alternates', sans-serif;">A fast, lightw<wbr>eight pr<wbr>oxy developed by <strong>Nath<wbr>an Fri<wbr>edly</strong></p>
|
||||
<div id="url" class="input-group">
|
||||
<div class="input-group-prepend"></div><input id="url" class="bg-white border rounded-0 border-warning shadow-lg form-control form-control-lg" type="text" name="url" value="https://google.com" inputmode="url" style="width: 194px;font-family: 'Montserrat Alternates', sans-serif;">
|
||||
<div class="input-group-append"><button class="btn btn-dark btn-lg bg-dark border rounded-0 border-warning shadow-lg" type="submit" style="width: 97px;padding: 8px;margin: 0px;height: 48px;font-family: 'Montserrat Alternates', sans-serif;font-size: 14px;">Nod<wbr>e</button></div>
|
||||
</div>
|
||||
<div>
|
||||
<script>
|
||||
function $(id) {
|
||||
return document.getElementById(id);
|
||||
}
|
||||
|
||||
$('unblocker-form').onsubmit = function() {
|
||||
var url = $('url').value;
|
||||
var det = document.domain;
|
||||
var domain = det.replace('www.', '').split(/[/?#]/)[0];
|
||||
window.location.href = "https://a." + domain + "/call/" + url;
|
||||
return false;
|
||||
|
||||
if (url.substr(0, 4) != "http") {
|
||||
url = "http://a." + url;
|
||||
}
|
||||
window.location.pathname = 'b?url=' + url;
|
||||
return false;
|
||||
};
|
||||
|
||||
function checkError() {
|
||||
var search = window.location.search;
|
||||
var start = search.indexOf('error=');
|
||||
if (start > -1) {
|
||||
var stop = search.indexOf('&', start);
|
||||
if (stop == -1) {
|
||||
stop = undefined;
|
||||
}
|
||||
// +6 for "error="
|
||||
var err = search.substr(start + 6, stop);
|
||||
var $error = $('error');
|
||||
$error.innerText = $error.textContent = decodeURIComponent(err);
|
||||
$error.style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
$('url').focus();
|
||||
checkError();
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
<p style="font-size: 20px;font-family: 'Montserrat Alternates', sans-serif;">More Information:<br></p>
|
||||
<p>Flex<wbr>ible proxy but A<wbr>lloy Pr<wbr>oxy is better.<br>Use if you have any iss<wbr>ues with A<wbr>lloy.</p>
|
||||
<p>GitHub: <a class="text-danger" href="#"><strong><span style="text-decoration: underline;">https://github.com/nfriedly/node-unblocker</span></strong></a><br></p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-dark" style="background-color: rgb(0,0,0);">
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 item text">
|
||||
<h3>Holy Unbl<wbr>oc<wbr>ker</h3>
|
||||
<p>Made by Stu<wbr>dents, For Stu<wbr>dents. </p>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 item">
|
||||
<h3>Services</h3>
|
||||
<ul>
|
||||
<li><a href="/a.html">A<wbr>lloy</a></li>
|
||||
<li><a href="/b.html">No<wbr>de</a></li>
|
||||
<li><a href="https://nodeclusters.com/">NodeClust<wbr>ers</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 item">
|
||||
<h3>About</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic">GitHub</a></li>
|
||||
<li><a href="c.html">Support</a></li>
|
||||
<li><a href="c.html">Credits</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col item social"><a href="https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic"><i class="icon ion-social-github-outline" style="font-family: 'Montserrat Alternates', sans-serif;"></i></a></div>
|
||||
</div>
|
||||
<p class="copyright">Holy U<wbr>nblo<wbr>cke<wbr>r © 2020</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/header.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
96
public/c.html
Normal file
96
public/c.html
Normal file
|
@ -0,0 +1,96 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||
<title>Launch Meeting − Zoom</title>
|
||||
<meta name="description" content="Get past internet censorship today!
|
||||
|
||||
:D">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="assets/img/icon.png">
|
||||
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat+Alternates">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium+Web:400,600,700">
|
||||
<link rel="stylesheet" href="assets/fonts/ionicons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/Customizable-Background--Overlay.css">
|
||||
<link rel="stylesheet" href="assets/css/Footer-Dark.css">
|
||||
<link rel="stylesheet" href="assets/css/Header-Dark.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<div class="header-dark" style="background-color: rgb(0,0,0);background-image: url("assets/img/black.jpg");">
|
||||
<nav class="navbar navbar-dark navbar-expand-lg navigation-clean-search">
|
||||
<div class="container"><a class="navbar-brand" style="font-family: 'Montserrat Alternates', sans-serif;font-size: 21px;margin: 10px;font-style: normal;font-weight: bold;" href="/index.html">Holy Un<wbr>blo<wbr>cker</a><button data-toggle="collapse" class="navbar-toggler"
|
||||
data-target="#navcol-1"><span class="sr-only">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
|
||||
<div class="collapse navbar-collapse" id="navcol-1">
|
||||
<ul class="nav navbar-nav ml-auto">
|
||||
<li class="nav-item" role="presentation"><a class="nav-link active" href="/z.html">Su<wbr>rf Fre<wbr>ely</a></li>
|
||||
<li class="nav-item" role="presentation"><a class="nav-link" href="g.html">Ga<wbr>mes</a></li>
|
||||
<li class="nav-item" role="presentation"><a class="nav-link" href="/yt.html">You<wbr>Tube</a></li>
|
||||
<li class="nav-item dropdown"><a class="dropdown-toggle nav-link" data-toggle="dropdown" aria-expanded="false" href="#">More</a>
|
||||
<div class="dropdown-menu" role="menu" style="background-color: rgb(33,30,30);font-family: 'Titillium Web', sans-serif;"><a class="dropdown-item" role="presentation" href="/k.html" style="color: rgb(255,255,255);">Kru<wbr>nker</a><a class="dropdown-item" role="presentation" href="/c.html" style="color: rgb(255,255,255);">Credits</a></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="particles-js" style="background-image: url("assets/img/black.jpg");height: 500px;background-position: center;background-size: cover;background-repeat: no-repeat;background-color: #000000;font-family: 'Montserrat Alternates', sans-serif;font-weight: bold;">
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: 85%;min-height: initial;width: 100%;position: absolute;left: 0;">
|
||||
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
|
||||
<script>
|
||||
/* particlesJS.load(@dom-id, @path-json, @callback (optional)); */
|
||||
particlesJS.load('particles-js', 'particles.json', function() {
|
||||
console.log('particlesjs loaded.......');
|
||||
});
|
||||
</script>
|
||||
<div class="text-center d-flex align-items-center order-12" style="height: 201px;width: 600px;">
|
||||
<div class="container text-center justify-content-center align-items-center" style="color: rgb(255,255,255);">
|
||||
<h1 class="text-center d-md-flex flex-grow-1 justify-content-md-center align-items-md-center" style="color: rgb(242,245,248);font-size: 46px;font-weight: normal;font-family: 'Montserrat Alternates', sans-serif;margin: 7px;padding: 34px;width: 555px;filter: blur(0px);height: 71px;">Credits<br></h1>
|
||||
<p><br> Quite A Fancy Emerald (Creator and Owner)<br><br><strong>−−</strong><br>Notable Mentions:<br>− SexyDuceDuce (Helped out a bunch)<br><strong>− OlyB (Also helped out a bunch)</strong><br><strong>− LQ16 (Creator of TN, Retired)</strong><br>−Shirt
|
||||
(Owner of TN)<br>− Mik<wbr>eLime (<strong>Co-Owner of Tit<wbr>anium<wbr>Ne<wbr>twork & Mass Pr<wbr>o<wbr>xy Site Maker, Web Developer, and Software Developer</strong>) :D<br>− Soup (Cat Lady) hehe<br>− YOCTDONALD'S
|
||||
(Obfuscation God, TN Bughunter)
|
||||
<br><strong>− Na<wbr>vvy (Web Developer, Mass Pr<wbr>oxy Site Maker)</strong><br><strong>−−</strong><br>And everyone else on TN :D<br><br>And of course a certain Michael<br><br></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-dark" style="background-color: rgb(0,0,0);">
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 item text">
|
||||
<h3>Ho<wbr>ly Unbl<wbr>oc<wbr>ker</h3>
|
||||
<p>Made by Stu<wbr>dents, For Studen<wbr>ts. </p>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 item">
|
||||
<h3>Services</h3>
|
||||
<ul>
|
||||
<li><a href="/a.html">Al<wbr>loy</a></li>
|
||||
<li><a href="/b.html">No<wbr>de</a></li>
|
||||
<li><a href="https://nodeclusters.com/">NodeClusters</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 item">
|
||||
<h3>About</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic">GitHub</a></li>
|
||||
<li><a href="c.html">Support</a></li>
|
||||
<li><a href="c.html">Credits</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col item social"><a href="https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic"><i class="icon ion-social-github-outline" style="font-family: 'Montserrat Alternates', sans-serif;"></i></a></div>
|
||||
</div>
|
||||
<p class="copyright">H<wbr>oly Unbl<wbr>ocker © 2020</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/header.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
82
public/css/style.css
Normal file
82
public/css/style.css
Normal file
|
@ -0,0 +1,82 @@
|
|||
.gembed {
|
||||
width: 80%;
|
||||
height: 800%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.fbody {
|
||||
background-color: black;
|
||||
color: rgb(0, 0, 0);
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.glink {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font: 18px;
|
||||
border: 1px solid rgb(255, 166, 0);
|
||||
margin-top: -1px;
|
||||
background-color: #000000;
|
||||
padding: 12px;
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
.glink:hover {
|
||||
background-color: rgb(0, 0, 0);
|
||||
text-shadow: 0 0 5px rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
#gsearchbar {
|
||||
outline: none;
|
||||
width: 374px;
|
||||
top: 12px;
|
||||
font-size: 16px;
|
||||
border: 1px solid rgba(255, 115, 0, 0.3);
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
#gsearchbar:focus {
|
||||
background-color: rgb(29, 27, 27);
|
||||
box-shadow: inset 0 0 5px 1px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.box {
|
||||
margin: auto;
|
||||
background-color: wblack;
|
||||
padding: 10px 10px 15px 10px;
|
||||
width: 420px;
|
||||
height: 540px;
|
||||
}
|
||||
|
||||
#glist {
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
width: 400px;
|
||||
height: 520px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#glist h2 {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font: 18px;
|
||||
border: 1px solid #060606;
|
||||
margin: -1px 0 0 0;
|
||||
background-color: #060606;
|
||||
padding: 12px;
|
||||
font-weight: bold;
|
||||
user-select: none;
|
||||
}
|
362
public/g.html
Normal file
362
public/g.html
Normal file
|
@ -0,0 +1,362 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||
<title>Launch Meeting − Zoom</title>
|
||||
<meta name="description" content="Get past internet censorship today!
|
||||
|
||||
:D">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="assets/img/icon.png">
|
||||
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat+Alternates">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium+Web:400,600,700">
|
||||
<link rel="stylesheet" href="/assets/fonts/ionicons.min.css">
|
||||
<link rel="stylesheet" href="/assets/css/Button-Change-Text-on-Hover.css">
|
||||
<link rel="stylesheet" href="/assets/css/Customizable-Background--Overlay.css">
|
||||
<link rel="stylesheet" href="/assets/css/Footer-Dark.css">
|
||||
<link rel="stylesheet" href="/assets/css/Header-Dark.css">
|
||||
<link rel="stylesheet" href="/assets/css/iframe.css">
|
||||
<link rel="stylesheet" href="/assets/css/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<style>
|
||||
.gembed {
|
||||
width: 80%;
|
||||
height: 800%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.fbody {
|
||||
background-color: black;
|
||||
color: rgb(0, 0, 0);
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.glink {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font: 18px;
|
||||
border: 1px solid rgb(255, 166, 0);
|
||||
margin-top: -1px;
|
||||
background-color: #000000;
|
||||
padding: 12px;
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
.glink:hover {
|
||||
background-color: rgb(0, 0, 0);
|
||||
text-shadow: 0 0 5px rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
#gsearchbar {
|
||||
outline: none;
|
||||
width: 374px;
|
||||
top: 12px;
|
||||
font-size: 16px;
|
||||
border: 1px solid rgba(255, 115, 0, 0.3);
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
transition: 0.2s ease;
|
||||
}
|
||||
|
||||
#gsearchbar:focus {
|
||||
background-color: rgb(29, 27, 27);
|
||||
box-shadow: inset 0 0 5px 1px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.box {
|
||||
margin: auto;
|
||||
background-color: wblack;
|
||||
padding: 10px 10px 15px 10px;
|
||||
width: 420px;
|
||||
height: 540px;
|
||||
}
|
||||
|
||||
#glist {
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
width: 400px;
|
||||
height: 520px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#glist h2 {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font: 18px;
|
||||
border: 1px solid #060606;
|
||||
margin: -1px 0 0 0;
|
||||
background-color: #060606;
|
||||
padding: 12px;
|
||||
font-weight: bold;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
<div class="header-dark" style="background-color: rgb(0,0,0);background-image: url("assets/img/black.jpg");">
|
||||
<nav class="navbar navbar-dark navbar-expand-lg navigation-clean-search">
|
||||
<div class="container"><a class="navbar-brand" style="font-family: 'Montserrat Alternates', sans-serif;font-size: 21px;margin: 10px;font-style: normal;font-weight: bold;" href="/index.html">Ho<wbr>ly Unbl<wbr>oc<wbr>ker</a>
|
||||
<div class="collapse navbar-collapse" id="navcol-1">
|
||||
<ul class="nav navbar-nav ml-auto">
|
||||
<li class="nav-item" role="presentation"><a class="nav-link active" href="/z.html">Surf Fre<wbr>ely</a></li>
|
||||
<li class="nav-item" role="presentation"><a class="nav-link" href="/g.html">Ga<wbr>mes</a></li>
|
||||
<li class="nav-item" role="presentation"><a class="nav-link" href="/yt.html">YouT<wbr>ube</a></li>
|
||||
<li class="nav-item dropdown"><a class="dropdown-toggle nav-link" data-toggle="dropdown" aria-expanded="false" href="#">More</a>
|
||||
<div class="dropdown-menu" role="menu" style="background-color: rgb(33,30,30);font-family: 'Titillium Web', sans-serif;"><a class="dropdown-item" role="presentation" href="/k.html" style="color: rgb(255,255,255);">Krunker</a><a class="dropdown-item" role="presentation" href="/c.html" style="color: rgb(255,255,255);">Credits</a></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="particles-js" style="height: 500px;">
|
||||
<div class="d-flex justify-content-center align-items-center" style="height: inherit;min-height: initial;width: 100%;position: absolute;left: 0;">
|
||||
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js "></script>
|
||||
<script>
|
||||
/* particlesJS.load(@dom-id, @path-json, @callback (optional)); */
|
||||
particlesJS.load('particles-js', 'particles.json', function() {
|
||||
console.log('particlesjs loaded.......');
|
||||
});
|
||||
</script>
|
||||
<div class="container">
|
||||
<div class="box">
|
||||
<input type="text" id="gsearchbar" onkeyup="gsearch()" autocomplete="off" placeholder="Search" />
|
||||
<div id="glist">
|
||||
<h2>HTML5 Games</h2>
|
||||
<a class="glink" href="./gfiles/html5games/2048">2<wbr>048</a>
|
||||
<a class="glink" href="./gfiles/html5games/asteroids">Aste<wbr>roids</a>
|
||||
<a class="glink" href="./gfiles/html5games/astray">Ast<wbr>ray</a>
|
||||
<a class="glink" href="./gfiles/html5games/backcountry">Bac<wbr>kcountry</a>
|
||||
<a class="glink" href="./gfiles/html5games/bounceback">Boun<wbr>ceback</a>
|
||||
<a class="glink" href="./gfiles/html5games/breaklock">Brea<wbr>klock</a>
|
||||
<a class="glink" href="./gfiles/html5games/breakout">Bre<wbr>akout</a>
|
||||
<a class="glink" href="./gfiles/html5games/chess">Che<wbr>ss</a>
|
||||
<a class="glink" href="./gfiles/html5games/chromaincident">Chroma<wbr>incident</a>
|
||||
<a class="glink" href="./gfiles/html5games/connect3">Conn<wbr>ect3</a>
|
||||
<a class="glink" href="./gfiles/html5games/cookieclicker">Cook<wbr>ieclicker</a>
|
||||
<a class="glink" href="./gfiles/html5games/evilglitch">Evilg<wbr>litch</a>
|
||||
<a class="glink" href="./gfiles/html5games/factoryballsforever">Fact<wbr>oryballsf<wbr>orever</a>
|
||||
<a class="glink" href="./gfiles/html5games/flappybird">Flap<wbr>pybird</a>
|
||||
<a class="glink" href="./gfiles/html5games/geometrydash">Geomet<wbr>rydash</a>
|
||||
<a class="glink" href="./gfiles/html5games/hextris">He<wbr>xtris</a>
|
||||
<a class="glink" href="./gfiles/html5games/konnekt">Kon<wbr>nekt</a>
|
||||
<a class="glink" href="./gfiles/html5games/krunker">Kru<wbr>nker</a>
|
||||
<a class="glink" href="./gfiles/html5games/linuxvm">Lin<wbr>uxvm</a>
|
||||
<a class="glink" href="./gfiles/html5games/pushback">Pus<wbr>hback</a>
|
||||
<a class="glink" href="./gfiles/html5games/racer">Rac<wbr>er</a>
|
||||
<a class="glink" href="./gfiles/html5games/radiusraid">Radi<wbr>usraid</a>
|
||||
<a class="glink" href="./gfiles/html5games/retrohaunt">Ret<wbr>rohaunt</a>
|
||||
<a class="glink" href="./gfiles/html5games/roadblocks">Road<wbr>blocks</a>
|
||||
<a class="glink" href="./gfiles/html5games/run3">Ru<wbr>n3</a>
|
||||
<a class="glink" href="./gfiles/html5games/sleepingbeauty">Slee<wbr>pingbeauty</a>
|
||||
<a class="glink" href="./gfiles/html5games/snake">Sn<wbr>ake</a>
|
||||
<a class="glink" href="./gfiles/html5games/spacecompany">Spacec<wbr>ompany</a>
|
||||
<a class="glink" href="./gfiles/html5games/tetris">Te<wbr>tris</a>
|
||||
<a class="glink" href="./gfiles/html5games/towermaster">Towerm<wbr>aster</a>
|
||||
<a class="glink" href="./gfiles/html5games/underrun">Under<wbr>run</a>
|
||||
<a class="glink" href="./gfiles/html5games/xx142-b2exe">Xx1<wbr>42-b2exe</a>
|
||||
<h2>Gameboy Advance</h2>
|
||||
<a class="glink" href="./gfiles/gba/">Upl<wbr>oad R<wbr>OM</a>
|
||||
<h2>Nintendo</h2>
|
||||
<a class="glink" href="./gfiles/nes/">Uplo<wbr>ad R<wbr>OM</a>
|
||||
<h2>Super Nintendo</h2>
|
||||
<a class="glink" href="./gfiles/snes/">Upl<wbr>oad RO<wbr>M</a>
|
||||
<h2>Flash Games</h2>
|
||||
<a class="glink" href="./gfiles/f.html#1on1soccer">1<wbr>on1<wbr>soccer</a>
|
||||
<a class="glink" href="./gfiles/f.html#3dtanks">3dta<wbr>nks</a>
|
||||
<a class="glink" href="./gfiles/f.html#abobosbigadventure">Abobosb<wbr>igadventure</a>
|
||||
<a class="glink" href="./gfiles/f.html#achievementunlocked">Achi<wbr>evementu<wbr>nlocked</a>
|
||||
<a class="glink" href="./gfiles/f.html#achievementunlocked2">Achi<wbr>evementunlo<wbr>cked2</a>
|
||||
<a class="glink" href="./gfiles/f.html#achievementunlocked3">Achievementunl<wbr>ocked3</a>
|
||||
<a class="glink" href="./gfiles/f.html#actionturnip">Actiont<wbr>urnip</a>
|
||||
<a class="glink" href="./gfiles/f.html#adaran">Ada<wbr>ran</a>
|
||||
<a class="glink" href="./gfiles/f.html#adrenaline">Adren<wbr>aline</a>
|
||||
<a class="glink" href="./gfiles/f.html#americanracing1">Americ<wbr>anracing1</a>
|
||||
<a class="glink" href="./gfiles/f.html#americanracing2">Americanracing2</a>
|
||||
<a class="glink" href="./gfiles/f.html#arkandianrevenant">Arka<wbr>ndianrevenant</a>
|
||||
<a class="glink" href="./gfiles/f.html#awesomecars">Aweso<wbr>mecars</a>
|
||||
<a class="glink" href="./gfiles/f.html#awesomeplanes">Aweso<wbr>meplanes</a>
|
||||
<a class="glink" href="./gfiles/f.html#bloonsplayerpack2">Bloo<wbr>nspla<wbr>yerpack2</a>
|
||||
<a class="glink" href="./gfiles/f.html#bloonsplayerpack3">Bloon<wbr>splayerpack3</a>
|
||||
<a class="glink" href="./gfiles/f.html#bloonsplayerpack4">Bloonsplay<wbr>erpack4</a>
|
||||
<a class="glink" href="./gfiles/f.html#bloonsplayerpack5">Blo<wbr>onspla<wbr>yerpack5</a>
|
||||
<a class="glink" href="./gfiles/f.html#bloonstd1">Bloo<wbr>nstd1</a>
|
||||
<a class="glink" href="./gfiles/f.html#bloonstd3">Bloo<wbr>nstd3</a>
|
||||
<a class="glink" href="./gfiles/f.html#bloonstd4">Blo<wbr>onstd4</a>
|
||||
<a class="glink" href="./gfiles/f.html#bloonstd5">Bl<wbr>oonstd5</a>
|
||||
<a class="glink" href="./gfiles/f.html#bobtherobber">Bobthe<wbr>robber</a>
|
||||
<a class="glink" href="./gfiles/f.html#boombot2">Boom<wbr>bot2</a>
|
||||
<a class="glink" href="./gfiles/f.html#boxhead2play">Boxh<wbr>ead2play</a>
|
||||
<a class="glink" href="./gfiles/f.html#bubbletanks2">Bubb<wbr>letanks2</a>
|
||||
<a class="glink" href="./gfiles/f.html#bulletbill">Bulle<wbr>tbill</a>
|
||||
<a class="glink" href="./gfiles/f.html#cactusmccoy">Cact<wbr>usmccoy</a>
|
||||
<a class="glink" href="./gfiles/f.html#cactusmccoy2">Cac<wbr>tusmccoy2</a>
|
||||
<a class="glink" href="./gfiles/f.html#cargobridge">Carg<wbr>obridge</a>
|
||||
<a class="glink" href="./gfiles/f.html#causality">Caus<wbr>ality</a>
|
||||
<a class="glink" href="./gfiles/f.html#computerbashing">Com<wbr>puterbashing</a>
|
||||
<a class="glink" href="./gfiles/f.html#crushthecastle">Cru<wbr>shthecastle</a>
|
||||
<a class="glink" href="./gfiles/f.html#cubefield">Cube<wbr>field</a>
|
||||
<a class="glink" href="./gfiles/f.html#cyclomaniacs2">Cyc<wbr>lomaniacs2</a>
|
||||
<a class="glink" href="./gfiles/f.html#diggy">Di<wbr>ggy</a>
|
||||
<a class="glink" href="./gfiles/f.html#donkeykong">Don<wbr>keykong</a>
|
||||
<a class="glink" href="./gfiles/f.html#dontshootthepuppy">Dont<wbr>shootthepuppy</a>
|
||||
<a class="glink" href="./gfiles/f.html#doodledefender">Doodl<wbr>edefender</a>
|
||||
<a class="glink" href="./gfiles/f.html#doom">Do<wbr>om</a>
|
||||
<a class="glink" href="./gfiles/f.html#ducklife">Duc<wbr>klife</a>
|
||||
<a class="glink" href="./gfiles/f.html#ducklife2">Duckl<wbr>ife2</a>
|
||||
<a class="glink" href="./gfiles/f.html#ducklife3">Du<wbr>cklife3</a>
|
||||
<a class="glink" href="./gfiles/f.html#ducklife4">Duckl<wbr>ife4</a>
|
||||
<a class="glink" href="./gfiles/f.html#earntodiesuperwheel">Earnt<wbr>odi<wbr>esuperwheel</a>
|
||||
<a class="glink" href="./gfiles/f.html#electricman2">Electri<wbr>cman2</a>
|
||||
<a class="glink" href="./gfiles/f.html#elephantquest">Elephantq<wbr>uest</a>
|
||||
<a class="glink" href="./gfiles/f.html#epicbattlefantasy3">Epicb<wbr>attlefantasy3</a>
|
||||
<a class="glink" href="./gfiles/f.html#epiccomboredux">Epicco<wbr>mboredux</a>
|
||||
<a class="glink" href="./gfiles/f.html#exitpath">Exit<wbr>path</a>
|
||||
<a class="glink" href="./gfiles/f.html#factoryballs">Factory<wbr>balls</a>
|
||||
<a class="glink" href="./gfiles/f.html#factoryballs2">Fact<wbr>oryballs2</a>
|
||||
<a class="glink" href="./gfiles/f.html#factoryballs3">Factorybal<wbr>ls3</a>
|
||||
<a class="glink" href="./gfiles/f.html#factoryballs4">Fa<wbr>ctoryballs4</a>
|
||||
<a class="glink" href="./gfiles/f.html#flashflightsimulator">Flash<wbr>flightsim<wbr>ulator</a>
|
||||
<a class="glink" href="./gfiles/f.html#flight">Fl<wbr>ight</a>
|
||||
<a class="glink" href="./gfiles/f.html#happywheels">Hap<wbr>pywhee<wbr>ls</a>
|
||||
<a class="glink" href="./gfiles/f.html#hobo">Ho<wbr>bo</a>
|
||||
<a class="glink" href="./gfiles/f.html#hobo2">Ho<wbr>bo2</a>
|
||||
<a class="glink" href="./gfiles/f.html#hobo3">H<wbr>obo3</a>
|
||||
<a class="glink" href="./gfiles/f.html#hobo4">H<wbr>obo4</a>
|
||||
<a class="glink" href="./gfiles/f.html#hobo5">H<wbr>obo5</a>
|
||||
<a class="glink" href="./gfiles/f.html#hobo6">Ho<wbr>bo6</a>
|
||||
<a class="glink" href="./gfiles/f.html#hobo7">Hob<wbr>o7</a>
|
||||
<a class="glink" href="./gfiles/f.html#interactivebuddy">Int<wbr>eractivebuddy</a>
|
||||
<a class="glink" href="./gfiles/f.html#jacksmith">Jacksm<wbr>ith</a>
|
||||
<a class="glink" href="./gfiles/f.html#jellytruck">Jell<wbr>ytruck</a>
|
||||
<a class="glink" href="./gfiles/f.html#johnnyupgrade">John<wbr>nyupgrade</a>
|
||||
<a class="glink" href="./gfiles/f.html#jumpix2">Jum<wbr>pix2</a>
|
||||
<a class="glink" href="./gfiles/f.html#learn2fly">Lear<wbr>n2fly</a>
|
||||
<a class="glink" href="./gfiles/f.html#magnetface">Mag<wbr>netface</a>
|
||||
<a class="glink" href="./gfiles/f.html#marioracingtournament">Mari<wbr>oracingtournament</a>
|
||||
<a class="glink" href="./gfiles/f.html#megamanprojectx">Mega<wbr>manprojectx</a>
|
||||
<a class="glink" href="./gfiles/f.html#metroidelements">Metroid<wbr>elements</a>
|
||||
<a class="glink" href="./gfiles/f.html#mineblocks">Minebl<wbr>ocks</a>
|
||||
<a class="glink" href="./gfiles/f.html#minesweeper">Min<wbr>esweeper</a>
|
||||
<a class="glink" href="./gfiles/f.html#mirrorsedge">Mirr<wbr>orsedge</a>
|
||||
<a class="glink" href="./gfiles/f.html#motherload">Moth<wbr>erload</a>
|
||||
<a class="glink" href="./gfiles/f.html#multitask">Mu<wbr>ltitask</a>
|
||||
<a class="glink" href="./gfiles/f.html#mutilateadoll2">Muti<wbr>lateadoll2</a>
|
||||
<a class="glink" href="./gfiles/f.html#myangel">My<wbr>angel</a>
|
||||
<a class="glink" href="./gfiles/f.html#nanotube">Nano<wbr>tube</a>
|
||||
<a class="glink" href="./gfiles/f.html#ngame">Ng<wbr>ame</a>
|
||||
<a class="glink" href="./gfiles/f.html#nucleus">Nu<wbr>cleus</a>
|
||||
<a class="glink" href="./gfiles/f.html#nyancatlostinspace">Nyanca<wbr>tlostinspace</a>
|
||||
<a class="glink" href="./gfiles/f.html#onemanarmy2">One<wbr>manarmy2</a>
|
||||
<a class="glink" href="./gfiles/f.html#pacman">Pac<wbr>man</a>
|
||||
<a class="glink" href="./gfiles/f.html#pandemic">Pand<wbr>emic</a>
|
||||
<a class="glink" href="./gfiles/f.html#pandemic2">Pa<wbr>ndemic2</a>
|
||||
<a class="glink" href="./gfiles/f.html#papalouie">Pap<wbr>alouie</a>
|
||||
<a class="glink" href="./gfiles/f.html#papalouie2">Pa<wbr>palouie2</a>
|
||||
<a class="glink" href="./gfiles/f.html#papalouie3">Pap<wbr>alouie3</a>
|
||||
<a class="glink" href="./gfiles/f.html#portal">Port<wbr>al</a>
|
||||
<a class="glink" href="./gfiles/f.html#portal2d">Por<wbr>tal2d</a>
|
||||
<a class="glink" href="./gfiles/f.html#qwop">Q<wbr>wop</a>
|
||||
<a class="glink" href="./gfiles/f.html#raftwars">Raftw<wbr>ars</a>
|
||||
<a class="glink" href="./gfiles/f.html#raftwars2">Raf<wbr>twars2</a>
|
||||
<a class="glink" href="./gfiles/f.html#raze">R<wbr>aze</a>
|
||||
<a class="glink" href="./gfiles/f.html#redshift">Red<wbr>shift</a>
|
||||
<a class="glink" href="./gfiles/f.html#revenant2">Rev<wbr>enant2</a>
|
||||
<a class="glink" href="./gfiles/f.html#run2">R<wbr>un2</a>
|
||||
<a class="glink" href="./gfiles/f.html#run3">Ru<wbr>n3</a>
|
||||
<a class="glink" href="./gfiles/f.html#saszombieassault3">Saszombie<wbr>assault3</a>
|
||||
<a class="glink" href="./gfiles/f.html#shoppingcarthero3">Sh<wbr>oppingcarthero3</a>
|
||||
<a class="glink" href="./gfiles/f.html#siftheads">Sifthe<wbr>ads</a>
|
||||
<a class="glink" href="./gfiles/f.html#siftheads2">Si<wbr>ftheads2</a>
|
||||
<a class="glink" href="./gfiles/f.html#siftheads3">Sif<wbr>theads3</a>
|
||||
<a class="glink" href="./gfiles/f.html#siftheads4">Sifthe<wbr>ads4</a>
|
||||
<a class="glink" href="./gfiles/f.html#siftheads5">Sif<wbr>theads5</a>
|
||||
<a class="glink" href="./gfiles/f.html#sniperassassin4">Snipera<wbr>ssassin4</a>
|
||||
<a class="glink" href="./gfiles/f.html#sportsheadsfootball">Sportsh<wbr>eadsfootball</a>
|
||||
<a class="glink" href="./gfiles/f.html#stickrpg">Stic<wbr>krpg</a>
|
||||
<a class="glink" href="./gfiles/f.html#stickrun2">St<wbr>ickrun2</a>
|
||||
<a class="glink" href="./gfiles/f.html#stickwar">Sti<wbr>ckwar</a>
|
||||
<a class="glink" href="./gfiles/f.html#strikeforceheroes2">Strikeforce<wbr>heroes2</a>
|
||||
<a class="glink" href="./gfiles/f.html#strikeforcekittylaststand">Strikefor<wbr>cekittylaststand</a>
|
||||
<a class="glink" href="./gfiles/f.html#sugarsugar">Sugarsugar</a>
|
||||
<a class="glink" href="./gfiles/f.html#sugarsugar2">Sugarsugar2</a>
|
||||
<a class="glink" href="./gfiles/f.html#sugarsugar3">Sugarsu<wbr>gar3</a>
|
||||
<a class="glink" href="./gfiles/f.html#superd">Superd</a>
|
||||
<a class="glink" href="./gfiles/f.html#superfighters">Superfig<wbr>hters</a>
|
||||
<a class="glink" href="./gfiles/f.html#supermario63">Superm<wbr>ario63</a>
|
||||
<a class="glink" href="./gfiles/f.html#supermarioflash">Superma<wbr>rioflash</a>
|
||||
<a class="glink" href="./gfiles/f.html#swordsandsandals2">Swordsand<wbr>sandals2</a>
|
||||
<a class="glink" href="./gfiles/f.html#tacticalassassin">Tacticalassassin</a>
|
||||
<a class="glink" href="./gfiles/f.html#tanks">Tanks</a>
|
||||
<a class="glink" href="./gfiles/f.html#tanktrouble">Tanktrouble</a>
|
||||
<a class="glink" href="./gfiles/f.html#tetris">Te<wbr>tris</a>
|
||||
<a class="glink" href="./gfiles/f.html#thebindingofisaac">Thebindingofisaac</a>
|
||||
<a class="glink" href="./gfiles/f.html#theimpossiblequiz2">Theimpossi<wbr>blequiz2</a>
|
||||
<a class="glink" href="./gfiles/f.html#theworldshardestgame2">Thew<wbr>orldshardestgame2</a>
|
||||
<a class="glink" href="./gfiles/f.html#thingthingarena">Thingth<wbr>ingarena</a>
|
||||
<a class="glink" href="./gfiles/f.html#tosstheturtle">Tosst<wbr>he<wbr>turtle</a>
|
||||
<a class="glink" href="./gfiles/f.html#ultimateflashsonic">Ultima<wbr>teflashsonic</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function gsearch() {
|
||||
var e, t, n, a;
|
||||
for (e = document.getElementById("gsearchbar").value.toUpperCase(), t = document.getElementById("glist"), a = 0; a < t.querySelectorAll("a[href]").length; a++)(n = t.getElementsByTagName("a")[a]).innerHTML.toUpperCase().indexOf(e) > -1 ? n.style.display = "block" : n.style.display = "none"
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-dark" style="background-color: rgb(0,0,0);">
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 item text">
|
||||
<h3>Holy Unblo<wbr>cker</h3>
|
||||
<p>Made by Stu<wbr>dents, For Stud<wbr>ents. </p>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 item">
|
||||
<h3>Services</h3>
|
||||
<ul>
|
||||
<li><a href="/a.html">Al<wbr>loy</a></li>
|
||||
<li><a href="/b.html">No<wbr>de</a></li>
|
||||
<li><a href="https://nodeclusters.com/">NodeClu<wbr>sters</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3 item">
|
||||
<h3>About</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic">GitHub</a></li>
|
||||
<li><a href="c.html">Support</a></li>
|
||||
<li><a href="c.html">Credits</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col item social"><a href="https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic"><i class="icon ion-social-github-outline" style="font-family: 'Montserrat Alternates', sans-serif;"></i></a></div>
|
||||
</div>
|
||||
<p class="copyright">Holy Un<wbr>bloc<wbr>ker © 2020</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="assets/js/jquery.min.js"></script>
|
||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="assets/js/header.js"></script>
|
||||
<script src="assets/js/surf.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
1
public/gfiles/f.html
Normal file
1
public/gfiles/f.html
Normal file
|
@ -0,0 +1 @@
|
|||
<!DOCTYPE html><html><head><title>Flash Game</title><link rel="stylesheet" href="../css/style.css"><script>function loadswf(){var a,b,c; a="https://cdn.jsdelivr.net/gh/BinBashBanana/gstore/"; b=window.location.hash.substring(1)+".swf"; c=document.body; c.innerHTML='<object class="gembed" data="'+a+b+'" type="application/x-shockwave-flash"><param name="wmode" value="direct" /></object>';};</script></head><body onload="loadswf();" class="gbody"></body></html>
|
653
public/gfiles/gba/IodineGBA/core/CPU.js
Normal file
653
public/gfiles/gba/IodineGBA/core/CPU.js
Normal file
|
@ -0,0 +1,653 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceCPU(IOCore) {
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.initialize = function () {
|
||||
this.memory = this.IOCore.memory;
|
||||
this.wait = this.IOCore.wait;
|
||||
this.mul64ResultHigh = 0; //Scratch MUL64.
|
||||
this.mul64ResultLow = 0; //Scratch MUL64.
|
||||
this.initializeRegisters();
|
||||
this.ARM = new ARMInstructionSet(this);
|
||||
this.THUMB = new THUMBInstructionSet(this);
|
||||
//this.swi = new GameBoyAdvanceSWI(this);
|
||||
this.IOCore.assignInstructionCoreReferences(this.ARM, this.THUMB);
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.initializeRegisters = function () {
|
||||
/*
|
||||
R0-R7 Are known as the low registers.
|
||||
R8-R12 Are the high registers.
|
||||
R13 is the stack pointer.
|
||||
R14 is the link register.
|
||||
R15 is the program counter.
|
||||
CPSR is the program status register.
|
||||
SPSR is the saved program status register.
|
||||
*/
|
||||
//Normal R0-R15 Registers:
|
||||
this.registers = getInt32Array(16);
|
||||
//Used to copy back the R8-R14 state for normal operations:
|
||||
this.registersUSR = getInt32Array(7);
|
||||
//Fast IRQ mode registers (R8-R14):
|
||||
this.registersFIQ = getInt32Array(7);
|
||||
//Supervisor mode registers (R13-R14):
|
||||
this.registersSVC = getInt32Array(2);
|
||||
//Abort mode registers (R13-R14):
|
||||
this.registersABT = getInt32Array(2);
|
||||
//IRQ mode registers (R13-R14):
|
||||
this.registersIRQ = getInt32Array(2);
|
||||
//Undefined mode registers (R13-R14):
|
||||
this.registersUND = getInt32Array(2);
|
||||
//CPSR Register:
|
||||
this.branchFlags = ARMCPSRAttributeTable();
|
||||
this.modeFlags = 0xD3;
|
||||
//Banked SPSR Registers:
|
||||
this.SPSR = getUint16Array(5);
|
||||
this.SPSR[0] = 0xD3; //FIQ
|
||||
this.SPSR[1] = 0xD3; //IRQ
|
||||
this.SPSR[2] = 0xD3; //Supervisor
|
||||
this.SPSR[3] = 0xD3; //Abort
|
||||
this.SPSR[4] = 0xD3; //Undefined
|
||||
this.triggeredIRQ = 0; //Pending IRQ found.
|
||||
//Pre-initialize stack pointers if no BIOS loaded:
|
||||
if (this.IOCore.SKIPBoot) {
|
||||
this.HLEReset();
|
||||
}
|
||||
//Start in fully bubbled pipeline mode:
|
||||
this.IOCore.flagBubble();
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.HLEReset = function () {
|
||||
this.registersSVC[0] = 0x3007FE0;
|
||||
this.registersIRQ[0] = 0x3007FA0;
|
||||
this.registers[13] = 0x3007F00;
|
||||
this.registers[15] = 0x8000000;
|
||||
this.modeFlags = this.modeFlags | 0x1f;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.branch = function (branchTo) {
|
||||
branchTo = branchTo | 0;
|
||||
//if ((branchTo | 0) > 0x3FFF || this.IOCore.BIOSFound) {
|
||||
//Branch to new address:
|
||||
this.registers[15] = branchTo | 0;
|
||||
//Mark pipeline as invalid:
|
||||
this.IOCore.flagBubble();
|
||||
//Next PC fetch has to update the address bus:
|
||||
this.wait.NonSequentialBroadcastClear();
|
||||
/*}
|
||||
else {
|
||||
//We're branching into BIOS, handle specially:
|
||||
if ((branchTo | 0) == 0x130) {
|
||||
//IRQ mode exit handling:
|
||||
//ROM IRQ handling returns back from its own subroutine back to BIOS at this address.
|
||||
this.HLEIRQExit();
|
||||
}
|
||||
else {
|
||||
//Reset to start of ROM if no BIOS ROM found:
|
||||
this.HLEReset();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.triggerIRQ = function (didFire) {
|
||||
this.triggeredIRQ = didFire | 0;
|
||||
this.assertIRQ();
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.assertIRQ = function () {
|
||||
if ((this.triggeredIRQ | 0) != 0 && (this.modeFlags & 0x80) == 0) {
|
||||
this.IOCore.flagIRQ();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.getCurrentFetchValue = function () {
|
||||
if ((this.modeFlags & 0x20) != 0) {
|
||||
return this.THUMB.getCurrentFetchValue() | 0;
|
||||
}
|
||||
else {
|
||||
return this.ARM.getCurrentFetchValue() | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.enterARM = function () {
|
||||
this.modeFlags = this.modeFlags & 0xdf;
|
||||
this.THUMBBitModify(false);
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.enterTHUMB = function () {
|
||||
this.modeFlags = this.modeFlags | 0x20;
|
||||
this.THUMBBitModify(true);
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.getLR = function () {
|
||||
//Get the previous instruction address:
|
||||
if ((this.modeFlags & 0x20) != 0) {
|
||||
return this.THUMB.getLR() | 0;
|
||||
}
|
||||
else {
|
||||
return this.ARM.getLR() | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.THUMBBitModify = function (isThumb) {
|
||||
if (isThumb) {
|
||||
this.IOCore.flagTHUMB();
|
||||
}
|
||||
else {
|
||||
this.IOCore.deflagTHUMB();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.IRQinARM = function () {
|
||||
//Mode bits are set to IRQ:
|
||||
this.switchMode(0x12);
|
||||
//Save link register:
|
||||
this.registers[14] = this.ARM.getIRQLR() | 0;
|
||||
//Disable IRQ:
|
||||
this.modeFlags = this.modeFlags | 0x80;
|
||||
//if (this.IOCore.BIOSFound) {
|
||||
//IRQ exception vector:
|
||||
this.branch(0x18);
|
||||
/*}
|
||||
else {
|
||||
//HLE the IRQ entrance:
|
||||
this.HLEIRQEnter();
|
||||
}*/
|
||||
//Deflag IRQ from state:
|
||||
this.IOCore.deflagIRQ();
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.IRQinTHUMB = function () {
|
||||
//Mode bits are set to IRQ:
|
||||
this.switchMode(0x12);
|
||||
//Save link register:
|
||||
this.registers[14] = this.THUMB.getIRQLR() | 0;
|
||||
//Disable IRQ:
|
||||
this.modeFlags = this.modeFlags | 0x80;
|
||||
//Exception always enter ARM mode:
|
||||
this.enterARM();
|
||||
//if (this.IOCore.BIOSFound) {
|
||||
//IRQ exception vector:
|
||||
this.branch(0x18);
|
||||
/*}
|
||||
else {
|
||||
//HLE the IRQ entrance:
|
||||
this.HLEIRQEnter();
|
||||
}*/
|
||||
//Deflag IRQ from state:
|
||||
this.IOCore.deflagIRQ();
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.HLEIRQEnter = function () {
|
||||
//Get the base address:
|
||||
var currentAddress = this.registers[0xD] | 0;
|
||||
//Updating the address bus away from PC fetch:
|
||||
this.wait.NonSequentialBroadcast();
|
||||
//Push register(s) into memory:
|
||||
for (var rListPosition = 0xF; (rListPosition | 0) > -1; rListPosition = ((rListPosition | 0) - 1) | 0) {
|
||||
if ((0x500F & (1 << (rListPosition | 0))) != 0) {
|
||||
//Push a register into memory:
|
||||
currentAddress = ((currentAddress | 0) - 4) | 0;
|
||||
this.memory.memoryWrite32(currentAddress | 0, this.registers[rListPosition | 0] | 0);
|
||||
}
|
||||
}
|
||||
//Store the updated base address back into register:
|
||||
this.registers[0xD] = currentAddress | 0;
|
||||
//Updating the address bus back to PC fetch:
|
||||
this.wait.NonSequentialBroadcast();
|
||||
this.registers[0] = 0x4000000;
|
||||
//Save link register:
|
||||
this.registers[14] = 0x130;
|
||||
//Skip BIOS ROM processing:
|
||||
this.branch(this.read32(0x3FFFFFC) & -0x4);
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.HLEIRQExit = function () {
|
||||
//Get the base address:
|
||||
var currentAddress = this.registers[0xD] | 0;
|
||||
//Updating the address bus away from PC fetch:
|
||||
this.wait.NonSequentialBroadcast();
|
||||
//Load register(s) from memory:
|
||||
for (var rListPosition = 0; (rListPosition | 0) < 0x10; rListPosition = ((rListPosition | 0) + 1) | 0) {
|
||||
if ((0x500F & (1 << (rListPosition | 0))) != 0) {
|
||||
//Load a register from memory:
|
||||
this.registers[rListPosition & 0xF] = this.memory.memoryRead32(currentAddress | 0) | 0;
|
||||
currentAddress = ((currentAddress | 0) + 4) | 0;
|
||||
}
|
||||
}
|
||||
//Store the updated base address back into register:
|
||||
this.registers[0xD] = currentAddress | 0;
|
||||
//Updating the address bus back to PC fetch:
|
||||
this.wait.NonSequentialBroadcast();
|
||||
//Return from an exception mode:
|
||||
var data = this.branchFlags.setSUBFlags(this.registers[0xE] | 0, 4) | 0;
|
||||
//Restore SPSR to CPSR:
|
||||
data = data & (-4 >> (this.SPSRtoCPSR() >> 5));
|
||||
//We performed a branch:
|
||||
this.branch(data | 0);
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.SWI = function () {
|
||||
//if (this.IOCore.BIOSFound) {
|
||||
//Mode bits are set to SWI:
|
||||
this.switchMode(0x13);
|
||||
//Save link register:
|
||||
this.registers[14] = this.getLR() | 0;
|
||||
//Disable IRQ:
|
||||
this.modeFlags = this.modeFlags | 0x80;
|
||||
//Exception always enter ARM mode:
|
||||
this.enterARM();
|
||||
//SWI exception vector:
|
||||
this.branch(0x8);
|
||||
/*}
|
||||
else {
|
||||
if ((this.modeFlags & 0x20) != 0) {
|
||||
this.THUMB.incrementProgramCounter();
|
||||
//HLE the SWI command:
|
||||
this.swi.execute(this.THUMB.getSWICode() | 0);
|
||||
}
|
||||
else {
|
||||
this.ARM.incrementProgramCounter();
|
||||
//HLE the SWI command:
|
||||
this.swi.execute(this.ARM.getSWICode() | 0);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.UNDEFINED = function () {
|
||||
//Only process undefined instruction if BIOS loaded:
|
||||
//if (this.IOCore.BIOSFound) {
|
||||
//Mode bits are set to SWI:
|
||||
this.switchMode(0x1B);
|
||||
//Save link register:
|
||||
this.registers[14] = this.getLR() | 0;
|
||||
//Disable IRQ:
|
||||
this.modeFlags = this.modeFlags | 0x80;
|
||||
//Exception always enter ARM mode:
|
||||
this.enterARM();
|
||||
//Undefined exception vector:
|
||||
this.branch(0x4);
|
||||
/*}
|
||||
else {
|
||||
//Pretend we didn't execute the bad instruction then:
|
||||
if ((this.modeFlags & 0x20) != 0) {
|
||||
this.THUMB.incrementProgramCounter();
|
||||
}
|
||||
else {
|
||||
this.ARM.incrementProgramCounter();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.SPSRtoCPSR = function () {
|
||||
//Used for leaving an exception and returning to the previous state:
|
||||
var bank = 1;
|
||||
switch (this.modeFlags & 0x1f) {
|
||||
case 0x12: //IRQ
|
||||
break;
|
||||
case 0x13: //Supervisor
|
||||
bank = 2;
|
||||
break;
|
||||
case 0x11: //FIQ
|
||||
bank = 0;
|
||||
break;
|
||||
case 0x17: //Abort
|
||||
bank = 3;
|
||||
break;
|
||||
case 0x1B: //Undefined
|
||||
bank = 4;
|
||||
break;
|
||||
default: //User & system lacks SPSR
|
||||
return this.modeFlags & 0x20;
|
||||
}
|
||||
var spsr = this.SPSR[bank | 0] | 0;
|
||||
this.branchFlags.setNZCV(spsr << 20);
|
||||
this.switchRegisterBank(spsr & 0x1F);
|
||||
this.modeFlags = spsr & 0xFF;
|
||||
this.assertIRQ();
|
||||
this.THUMBBitModify((spsr & 0x20) != 0);
|
||||
return spsr & 0x20;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.switchMode = function (newMode) {
|
||||
newMode = newMode | 0;
|
||||
this.CPSRtoSPSR(newMode | 0);
|
||||
this.switchRegisterBank(newMode | 0);
|
||||
this.modeFlags = (this.modeFlags & 0xe0) | (newMode | 0);
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.CPSRtoSPSR = function (newMode) {
|
||||
//Used for entering an exception and saving the previous state:
|
||||
var spsr = this.modeFlags & 0xFF;
|
||||
spsr = spsr | (this.branchFlags.getNZCV() >> 20);
|
||||
switch (newMode | 0) {
|
||||
case 0x12: //IRQ
|
||||
this.SPSR[1] = spsr | 0;
|
||||
break;
|
||||
case 0x13: //Supervisor
|
||||
this.SPSR[2] = spsr | 0;
|
||||
break;
|
||||
case 0x11: //FIQ
|
||||
this.SPSR[0] = spsr | 0;
|
||||
break;
|
||||
case 0x17: //Abort
|
||||
this.SPSR[3] = spsr | 0;
|
||||
break;
|
||||
case 0x1B: //Undefined
|
||||
this.SPSR[4] = spsr | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.switchRegisterBank = function (newMode) {
|
||||
newMode = newMode | 0;
|
||||
switch (this.modeFlags & 0x1F) {
|
||||
case 0x10:
|
||||
case 0x1F:
|
||||
this.registersUSR[0] = this.registers[8] | 0;
|
||||
this.registersUSR[1] = this.registers[9] | 0;
|
||||
this.registersUSR[2] = this.registers[10] | 0;
|
||||
this.registersUSR[3] = this.registers[11] | 0;
|
||||
this.registersUSR[4] = this.registers[12] | 0;
|
||||
this.registersUSR[5] = this.registers[13] | 0;
|
||||
this.registersUSR[6] = this.registers[14] | 0;
|
||||
break;
|
||||
case 0x11:
|
||||
this.registersFIQ[0] = this.registers[8] | 0;
|
||||
this.registersFIQ[1] = this.registers[9] | 0;
|
||||
this.registersFIQ[2] = this.registers[10] | 0;
|
||||
this.registersFIQ[3] = this.registers[11] | 0;
|
||||
this.registersFIQ[4] = this.registers[12] | 0;
|
||||
this.registersFIQ[5] = this.registers[13] | 0;
|
||||
this.registersFIQ[6] = this.registers[14] | 0;
|
||||
break;
|
||||
case 0x12:
|
||||
this.registersUSR[0] = this.registers[8] | 0;
|
||||
this.registersUSR[1] = this.registers[9] | 0;
|
||||
this.registersUSR[2] = this.registers[10] | 0;
|
||||
this.registersUSR[3] = this.registers[11] | 0;
|
||||
this.registersUSR[4] = this.registers[12] | 0;
|
||||
this.registersIRQ[0] = this.registers[13] | 0;
|
||||
this.registersIRQ[1] = this.registers[14] | 0;
|
||||
break;
|
||||
case 0x13:
|
||||
this.registersUSR[0] = this.registers[8] | 0;
|
||||
this.registersUSR[1] = this.registers[9] | 0;
|
||||
this.registersUSR[2] = this.registers[10] | 0;
|
||||
this.registersUSR[3] = this.registers[11] | 0;
|
||||
this.registersUSR[4] = this.registers[12] | 0;
|
||||
this.registersSVC[0] = this.registers[13] | 0;
|
||||
this.registersSVC[1] = this.registers[14] | 0;
|
||||
break;
|
||||
case 0x17:
|
||||
this.registersUSR[0] = this.registers[8] | 0;
|
||||
this.registersUSR[1] = this.registers[9] | 0;
|
||||
this.registersUSR[2] = this.registers[10] | 0;
|
||||
this.registersUSR[3] = this.registers[11] | 0;
|
||||
this.registersUSR[4] = this.registers[12] | 0;
|
||||
this.registersABT[0] = this.registers[13] | 0;
|
||||
this.registersABT[1] = this.registers[14] | 0;
|
||||
break;
|
||||
case 0x1B:
|
||||
this.registersUSR[0] = this.registers[8] | 0;
|
||||
this.registersUSR[1] = this.registers[9] | 0;
|
||||
this.registersUSR[2] = this.registers[10] | 0;
|
||||
this.registersUSR[3] = this.registers[11] | 0;
|
||||
this.registersUSR[4] = this.registers[12] | 0;
|
||||
this.registersUND[0] = this.registers[13] | 0;
|
||||
this.registersUND[1] = this.registers[14] | 0;
|
||||
}
|
||||
switch (newMode | 0) {
|
||||
case 0x10:
|
||||
case 0x1F:
|
||||
this.registers[8] = this.registersUSR[0] | 0;
|
||||
this.registers[9] = this.registersUSR[1] | 0;
|
||||
this.registers[10] = this.registersUSR[2] | 0;
|
||||
this.registers[11] = this.registersUSR[3] | 0;
|
||||
this.registers[12] = this.registersUSR[4] | 0;
|
||||
this.registers[13] = this.registersUSR[5] | 0;
|
||||
this.registers[14] = this.registersUSR[6] | 0;
|
||||
break;
|
||||
case 0x11:
|
||||
this.registers[8] = this.registersFIQ[0] | 0;
|
||||
this.registers[9] = this.registersFIQ[1] | 0;
|
||||
this.registers[10] = this.registersFIQ[2] | 0;
|
||||
this.registers[11] = this.registersFIQ[3] | 0;
|
||||
this.registers[12] = this.registersFIQ[4] | 0;
|
||||
this.registers[13] = this.registersFIQ[5] | 0;
|
||||
this.registers[14] = this.registersFIQ[6] | 0;
|
||||
break;
|
||||
case 0x12:
|
||||
this.registers[8] = this.registersUSR[0] | 0;
|
||||
this.registers[9] = this.registersUSR[1] | 0;
|
||||
this.registers[10] = this.registersUSR[2] | 0;
|
||||
this.registers[11] = this.registersUSR[3] | 0;
|
||||
this.registers[12] = this.registersUSR[4] | 0;
|
||||
this.registers[13] = this.registersIRQ[0] | 0;
|
||||
this.registers[14] = this.registersIRQ[1] | 0;
|
||||
break;
|
||||
case 0x13:
|
||||
this.registers[8] = this.registersUSR[0] | 0;
|
||||
this.registers[9] = this.registersUSR[1] | 0;
|
||||
this.registers[10] = this.registersUSR[2] | 0;
|
||||
this.registers[11] = this.registersUSR[3] | 0;
|
||||
this.registers[12] = this.registersUSR[4] | 0;
|
||||
this.registers[13] = this.registersSVC[0] | 0;
|
||||
this.registers[14] = this.registersSVC[1] | 0;
|
||||
break;
|
||||
case 0x17:
|
||||
this.registers[8] = this.registersUSR[0] | 0;
|
||||
this.registers[9] = this.registersUSR[1] | 0;
|
||||
this.registers[10] = this.registersUSR[2] | 0;
|
||||
this.registers[11] = this.registersUSR[3] | 0;
|
||||
this.registers[12] = this.registersUSR[4] | 0;
|
||||
this.registers[13] = this.registersABT[0] | 0;
|
||||
this.registers[14] = this.registersABT[1] | 0;
|
||||
break;
|
||||
case 0x1B:
|
||||
this.registers[8] = this.registersUSR[0] | 0;
|
||||
this.registers[9] = this.registersUSR[1] | 0;
|
||||
this.registers[10] = this.registersUSR[2] | 0;
|
||||
this.registers[11] = this.registersUSR[3] | 0;
|
||||
this.registers[12] = this.registersUSR[4] | 0;
|
||||
this.registers[13] = this.registersUND[0] | 0;
|
||||
this.registers[14] = this.registersUND[1] | 0;
|
||||
}
|
||||
}
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceCPU.prototype.calculateMUL32 = Math.imul;
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceCPU.prototype.calculateMUL32 = function (rs, rd) {
|
||||
rs = rs | 0;
|
||||
rd = rd | 0;
|
||||
/*
|
||||
We have to split up the 32 bit multiplication,
|
||||
as JavaScript does multiplication on the FPU
|
||||
as double floats, which drops the low bits
|
||||
rather than the high bits.
|
||||
*/
|
||||
var lowMul = (rs & 0xFFFF) * rd;
|
||||
var highMul = (rs >> 16) * rd;
|
||||
//Cut off bits above bit 31 and return with proper sign:
|
||||
return ((highMul << 16) + lowMul) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.performMUL32 = function (rs, rd) {
|
||||
rs = rs | 0;
|
||||
rd = rd | 0;
|
||||
//Predict the internal cycle time:
|
||||
if ((rd >>> 8) == 0 || (rd >>> 8) == 0xFFFFFF) {
|
||||
this.IOCore.wait.CPUInternalSingleCyclePrefetch();
|
||||
}
|
||||
else if ((rd >>> 16) == 0 || (rd >>> 16) == 0xFFFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(2);
|
||||
}
|
||||
else if ((rd >>> 24) == 0 || (rd >>> 24) == 0xFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(3);
|
||||
}
|
||||
else {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(4);
|
||||
}
|
||||
return this.calculateMUL32(rs | 0, rd | 0) | 0;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.performMUL32MLA = function (rs, rd) {
|
||||
rs = rs | 0;
|
||||
rd = rd | 0;
|
||||
//Predict the internal cycle time:
|
||||
if ((rd >>> 8) == 0 || (rd >>> 8) == 0xFFFFFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(2);
|
||||
}
|
||||
else if ((rd >>> 16) == 0 || (rd >>> 16) == 0xFFFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(3);
|
||||
}
|
||||
else if ((rd >>> 24) == 0 || (rd >>> 24) == 0xFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(4);
|
||||
}
|
||||
else {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(5);
|
||||
}
|
||||
return this.calculateMUL32(rs | 0, rd | 0) | 0;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.performMUL64 = function (rs, rd) {
|
||||
rs = rs | 0;
|
||||
rd = rd | 0;
|
||||
//Predict the internal cycle time:
|
||||
if ((rd >>> 8) == 0 || (rd >>> 8) == 0xFFFFFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(2);
|
||||
}
|
||||
else if ((rd >>> 16) == 0 || (rd >>> 16) == 0xFFFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(3);
|
||||
}
|
||||
else if ((rd >>> 24) == 0 || (rd >>> 24) == 0xFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(4);
|
||||
}
|
||||
else {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(5);
|
||||
}
|
||||
//Solve for the high word (Do FPU double divide to bring down high word into the low word):
|
||||
this.mul64ResultHigh = Math.floor((rs * rd) / 0x100000000) | 0;
|
||||
this.mul64ResultLow = this.calculateMUL32(rs | 0, rd | 0) | 0;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.performMLA64 = function (rs, rd, mlaHigh, mlaLow) {
|
||||
rs = rs | 0;
|
||||
rd = rd | 0;
|
||||
mlaHigh = mlaHigh | 0;
|
||||
mlaLow = mlaLow | 0;
|
||||
//Predict the internal cycle time:
|
||||
if ((rd >>> 8) == 0 || (rd >>> 8) == 0xFFFFFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(3);
|
||||
}
|
||||
else if ((rd >>> 16) == 0 || (rd >>> 16) == 0xFFFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(4);
|
||||
}
|
||||
else if ((rd >>> 24) == 0 || (rd >>> 24) == 0xFF) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(5);
|
||||
}
|
||||
else {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(6);
|
||||
}
|
||||
//Solve for the high word (Do FPU double divide to bring down high word into the low word):
|
||||
var mulTop = Math.floor((rs * rd) / 0x100000000) | 0;
|
||||
var dirty = (this.calculateMUL32(rs | 0, rd | 0) >>> 0) + (mlaLow >>> 0);
|
||||
this.mul64ResultHigh = ((mulTop | 0) + (mlaHigh | 0) + Math.floor(dirty / 0x100000000)) | 0;
|
||||
this.mul64ResultLow = dirty | 0;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.performUMUL64 = function (rs, rd) {
|
||||
rs = rs | 0;
|
||||
rd = rd | 0;
|
||||
//Predict the internal cycle time:
|
||||
if ((rd >>> 8) == 0) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(2);
|
||||
}
|
||||
else if ((rd >>> 16) == 0) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(3);
|
||||
}
|
||||
else if ((rd >>> 24) == 0) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(4);
|
||||
}
|
||||
else {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(5);
|
||||
}
|
||||
//Solve for the high word (Do FPU double divide to bring down high word into the low word):
|
||||
this.mul64ResultHigh = (((rs >>> 0) * (rd >>> 0)) / 0x100000000) | 0;
|
||||
this.mul64ResultLow = this.calculateMUL32(rs | 0, rd | 0) | 0;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.performUMLA64 = function (rs, rd, mlaHigh, mlaLow) {
|
||||
rs = rs | 0;
|
||||
rd = rd | 0;
|
||||
mlaHigh = mlaHigh | 0;
|
||||
mlaLow = mlaLow | 0;
|
||||
//Predict the internal cycle time:
|
||||
if ((rd >>> 8) == 0) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(3);
|
||||
}
|
||||
else if ((rd >>> 16) == 0) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(4);
|
||||
}
|
||||
else if ((rd >>> 24) == 0) {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(5);
|
||||
}
|
||||
else {
|
||||
this.IOCore.wait.CPUInternalCyclePrefetch(6);
|
||||
}
|
||||
//Solve for the high word (Do FPU double divide to bring down high word into the low word):
|
||||
var mulTop = Math.floor(((rs >>> 0) * (rd >>> 0)) / 0x100000000) | 0;
|
||||
var dirty = (this.calculateMUL32(rs | 0, rd | 0) >>> 0) + (mlaLow >>> 0);
|
||||
this.mul64ResultHigh = ((mulTop | 0) + (mlaHigh | 0) + Math.floor(dirty / 0x100000000)) | 0;
|
||||
this.mul64ResultLow = dirty | 0;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.write32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
//Updating the address bus away from PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
this.memory.memoryWrite32(address | 0, data | 0);
|
||||
//Updating the address bus back to PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.write16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
//Updating the address bus away from PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
this.memory.memoryWrite16(address | 0, data | 0);
|
||||
//Updating the address bus back to PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.write8 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
//Updating the address bus away from PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
this.memory.memoryWrite8(address | 0, data | 0);
|
||||
//Updating the address bus back to PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.read32 = function (address) {
|
||||
address = address | 0;
|
||||
//Updating the address bus away from PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
var data = this.memory.memoryRead32(address | 0) | 0;
|
||||
//Unaligned access gets data rotated right:
|
||||
if ((address & 0x3) != 0) {
|
||||
//Rotate word right:
|
||||
data = (data << ((4 - (address & 0x3)) << 3)) | (data >>> ((address & 0x3) << 3));
|
||||
}
|
||||
//Updating the address bus back to PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.read16 = function (address) {
|
||||
address = address | 0;
|
||||
//Updating the address bus away from PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
var data = this.memory.memoryRead16(address | 0) | 0;
|
||||
//Unaligned access gets data rotated right:
|
||||
if ((address & 0x1) != 0) {
|
||||
//Rotate word right:
|
||||
data = (data << 24) | (data >>> 8);
|
||||
}
|
||||
//Updating the address bus back to PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCPU.prototype.read8 = function (address) {
|
||||
address = address | 0;
|
||||
//Updating the address bus away from PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
var data = this.memory.memoryRead8(address | 0) | 0;
|
||||
//Updating the address bus back to PC fetch:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
return data | 0;
|
||||
}
|
3687
public/gfiles/gba/IodineGBA/core/CPU/ARM.js
Normal file
3687
public/gfiles/gba/IodineGBA/core/CPU/ARM.js
Normal file
File diff suppressed because it is too large
Load diff
249
public/gfiles/gba/IodineGBA/core/CPU/CPSR.js
Normal file
249
public/gfiles/gba/IodineGBA/core/CPU/CPSR.js
Normal file
|
@ -0,0 +1,249 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2014 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function ARMCPSRAttributeTable() {
|
||||
//"use asm";
|
||||
var negative = 0;
|
||||
var zero = 1;
|
||||
var carry = 0;
|
||||
var overflow = 0;
|
||||
function setNegative(toSet) {
|
||||
toSet = toSet | 0;
|
||||
negative = toSet | 0;
|
||||
};
|
||||
function setNegativeFalse() {
|
||||
negative = 0;
|
||||
};
|
||||
function getNegative() {
|
||||
return negative | 0;
|
||||
};
|
||||
function setZero(toSet) {
|
||||
toSet = toSet | 0;
|
||||
zero = toSet | 0;
|
||||
};
|
||||
function setZeroTrue() {
|
||||
zero = 0;
|
||||
};
|
||||
function setZeroFalse() {
|
||||
zero = 1;
|
||||
};
|
||||
function getZero() {
|
||||
return zero | 0;
|
||||
};
|
||||
function setOverflowTrue() {
|
||||
overflow = -1;
|
||||
};
|
||||
function setOverflowFalse() {
|
||||
overflow = 0;
|
||||
};
|
||||
function getOverflow() {
|
||||
return overflow | 0;
|
||||
};
|
||||
function setCarry(toSet) {
|
||||
toSet = toSet | 0;
|
||||
carry = toSet | 0;
|
||||
};
|
||||
function setCarryFalse() {
|
||||
carry = 0;
|
||||
};
|
||||
function getCarry() {
|
||||
return carry | 0;
|
||||
};
|
||||
function getCarryReverse() {
|
||||
return (~carry) | 0;
|
||||
};
|
||||
function checkConditionalCode(execute) {
|
||||
execute = execute | 0;
|
||||
/*
|
||||
Instruction Decode Pattern:
|
||||
C = Conditional Code Bit;
|
||||
X = Possible opcode bit;
|
||||
N = Data Bit, definitely not an opcode bit
|
||||
OPCODE: CCCCXXXXXXXXXXXXNNNNNNNNXXXXNNNN
|
||||
|
||||
For this function, we decode the top 3 bits for the conditional code test:
|
||||
*/
|
||||
switch ((execute >>> 29) | 0) {
|
||||
case 0x4:
|
||||
if ((zero | 0) == 0) {
|
||||
execute = -1;
|
||||
break;
|
||||
}
|
||||
case 0x1:
|
||||
execute = ~carry;
|
||||
break;
|
||||
case 0x2:
|
||||
execute = ~negative;
|
||||
break;
|
||||
case 0x3:
|
||||
execute = ~overflow;
|
||||
break;
|
||||
case 0x6:
|
||||
if ((zero | 0) == 0) {
|
||||
execute = -1;
|
||||
break;
|
||||
}
|
||||
case 0x5:
|
||||
execute = negative ^ overflow;
|
||||
break;
|
||||
case 0x0:
|
||||
if ((zero | 0) != 0) {
|
||||
execute = -1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
execute = 0;
|
||||
}
|
||||
return execute | 0;
|
||||
};
|
||||
function setNZInt(toSet) {
|
||||
toSet = toSet | 0;
|
||||
negative = toSet | 0;
|
||||
zero = toSet | 0;
|
||||
};
|
||||
function setNZCV(toSet) {
|
||||
toSet = toSet | 0;
|
||||
negative = toSet | 0;
|
||||
zero = (~toSet) & 0x40000000;
|
||||
carry = toSet << 2;
|
||||
overflow = toSet << 3;
|
||||
};
|
||||
function getNZCV() {
|
||||
var toSet = 0;
|
||||
toSet = negative & 0x80000000;
|
||||
if ((zero | 0) == 0) {
|
||||
toSet = toSet | 0x40000000;
|
||||
}
|
||||
toSet = toSet | ((carry >>> 31) << 29);
|
||||
toSet = toSet | ((overflow >>> 31) << 28);
|
||||
return toSet | 0;
|
||||
};
|
||||
function setADDFlags(operand1, operand2) {
|
||||
//Update flags for an addition operation:
|
||||
operand1 = operand1 | 0;
|
||||
operand2 = operand2 | 0;
|
||||
negative = ((operand1 | 0) + (operand2 | 0)) | 0;
|
||||
zero = negative | 0;
|
||||
if ((negative >>> 0) < (operand1 >>> 0)) {
|
||||
carry = -1;
|
||||
}
|
||||
else {
|
||||
carry = 0;
|
||||
}
|
||||
overflow = (~(operand1 ^ operand2)) & (operand1 ^ negative);
|
||||
return negative | 0;
|
||||
};
|
||||
function setADCFlags(operand1, operand2) {
|
||||
//Update flags for an addition operation:
|
||||
operand1 = operand1 | 0;
|
||||
operand2 = operand2 | 0;
|
||||
negative = ((operand1 | 0) + (operand2 | 0)) | 0;
|
||||
negative = ((negative | 0) + (carry >>> 31)) | 0;
|
||||
zero = negative | 0;
|
||||
if ((negative >>> 0) < (operand1 >>> 0)) {
|
||||
carry = -1;
|
||||
}
|
||||
else if ((negative >>> 0) > (operand1 >>> 0)) {
|
||||
carry = 0;
|
||||
}
|
||||
overflow = (~(operand1 ^ operand2)) & (operand1 ^ negative);
|
||||
return negative | 0;
|
||||
};
|
||||
function setSUBFlags(operand1, operand2) {
|
||||
//Update flags for a subtraction operation:
|
||||
operand1 = operand1 | 0;
|
||||
operand2 = operand2 | 0;
|
||||
negative = ((operand1 | 0) - (operand2 | 0)) | 0;
|
||||
zero = negative | 0;
|
||||
if ((operand1 >>> 0) >= (operand2 >>> 0)) {
|
||||
carry = -1;
|
||||
}
|
||||
else {
|
||||
carry = 0;
|
||||
}
|
||||
overflow = (operand1 ^ operand2) & (operand1 ^ negative);
|
||||
return negative | 0;
|
||||
};
|
||||
function setSBCFlags(operand1, operand2) {
|
||||
//Update flags for a subtraction operation:
|
||||
operand1 = operand1 | 0;
|
||||
operand2 = operand2 | 0;
|
||||
negative = ((operand1 | 0) - (operand2 | 0)) | 0;
|
||||
negative = ((negative | 0) - ((~carry) >>> 31)) | 0
|
||||
zero = negative | 0;
|
||||
if ((negative >>> 0) < (operand1 >>> 0)) {
|
||||
carry = -1;
|
||||
}
|
||||
else if ((negative >>> 0) > (operand1 >>> 0)) {
|
||||
carry = 0;
|
||||
}
|
||||
overflow = (operand1 ^ operand2) & (operand1 ^ negative);
|
||||
return negative | 0;
|
||||
};
|
||||
function setCMPFlags(operand1, operand2) {
|
||||
//Update flags for a subtraction operation:
|
||||
operand1 = operand1 | 0;
|
||||
operand2 = operand2 | 0;
|
||||
negative = ((operand1 | 0) - (operand2 | 0)) | 0;
|
||||
zero = negative | 0;
|
||||
if ((operand1 >>> 0) >= (operand2 >>> 0)) {
|
||||
carry = -1;
|
||||
}
|
||||
else {
|
||||
carry = 0;
|
||||
}
|
||||
overflow = (operand1 ^ operand2) & (operand1 ^ negative);
|
||||
};
|
||||
function setCMNFlags(operand1, operand2) {
|
||||
//Update flags for an addition operation:
|
||||
operand1 = operand1 | 0;
|
||||
operand2 = operand2 | 0;
|
||||
negative = ((operand1 | 0) + (operand2 | 0)) | 0;
|
||||
zero = negative | 0;
|
||||
if ((negative >>> 0) < (operand1 >>> 0)) {
|
||||
carry = -1;
|
||||
}
|
||||
else {
|
||||
carry = 0;
|
||||
}
|
||||
overflow = (~(operand1 ^ operand2)) & (operand1 ^ negative);
|
||||
};
|
||||
function BGE() {
|
||||
//Branch if Negative equal to Overflow
|
||||
return (negative ^ overflow) | 0;
|
||||
};
|
||||
return {
|
||||
setNegative:setNegative,
|
||||
setNegativeFalse:setNegativeFalse,
|
||||
getNegative:getNegative,
|
||||
setZero:setZero,
|
||||
setZeroTrue:setZeroTrue,
|
||||
setZeroFalse:setZeroFalse,
|
||||
getZero:getZero,
|
||||
setOverflowTrue:setOverflowTrue,
|
||||
setOverflowFalse:setOverflowFalse,
|
||||
getOverflow:getOverflow,
|
||||
setCarry:setCarry,
|
||||
setCarryFalse:setCarryFalse,
|
||||
getCarry:getCarry,
|
||||
getCarryReverse:getCarryReverse,
|
||||
checkConditionalCode:checkConditionalCode,
|
||||
setNZInt:setNZInt,
|
||||
setNZCV:setNZCV,
|
||||
getNZCV:getNZCV,
|
||||
setADDFlags:setADDFlags,
|
||||
setADCFlags:setADCFlags,
|
||||
setSUBFlags:setSUBFlags,
|
||||
setSBCFlags:setSBCFlags,
|
||||
setCMPFlags:setCMPFlags,
|
||||
setCMNFlags:setCMNFlags,
|
||||
BGE:BGE
|
||||
};
|
||||
}
|
1493
public/gfiles/gba/IodineGBA/core/CPU/THUMB.js
Normal file
1493
public/gfiles/gba/IodineGBA/core/CPU/THUMB.js
Normal file
File diff suppressed because it is too large
Load diff
278
public/gfiles/gba/IodineGBA/core/Cartridge.js
Normal file
278
public/gfiles/gba/IodineGBA/core/Cartridge.js
Normal file
|
@ -0,0 +1,278 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2014 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceCartridge(IOCore) {
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.initialize = function () {
|
||||
this.flash_is128 = false;
|
||||
this.flash_isAtmel = false;
|
||||
this.ROM = this.getROMArray(this.IOCore.ROM);
|
||||
this.ROM16 = getUint16View(this.ROM);
|
||||
this.ROM32 = getInt32View(this.ROM);
|
||||
this.decodeName();
|
||||
this.decodeFlashType();
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.getROMArray = function (old_array) {
|
||||
this.ROMLength = Math.min((old_array.length >> 2) << 2, 0x2000000);
|
||||
this.EEPROMStart = ((this.ROMLength | 0) > 0x1000000) ? Math.max(this.ROMLength | 0, 0x1FFFF00) : 0x1000000;
|
||||
var newArray = getUint8Array(this.ROMLength | 0);
|
||||
for (var index = 0; (index | 0) < (this.ROMLength | 0); index = ((index | 0) + 1) | 0) {
|
||||
newArray[index | 0] = old_array[index | 0] | 0;
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.decodeName = function () {
|
||||
this.name = "GUID_";
|
||||
if ((this.ROMLength | 0) >= 0xC0) {
|
||||
for (var address = 0xAC; (address | 0) < 0xB3; address = ((address | 0) + 1) | 0) {
|
||||
if ((this.ROM[address | 0] | 0) > 0) {
|
||||
this.name += String.fromCharCode(this.ROM[address | 0] | 0);
|
||||
}
|
||||
else {
|
||||
this.name += "_";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.decodeFlashType = function () {
|
||||
this.flash_is128 = false;
|
||||
this.flash_isAtmel = false;
|
||||
var flash_types = 0;
|
||||
var F = ("F").charCodeAt(0) & 0xFF;
|
||||
var L = ("L").charCodeAt(0) & 0xFF;
|
||||
var A = ("A").charCodeAt(0) & 0xFF;
|
||||
var S = ("S").charCodeAt(0) & 0xFF;
|
||||
var H = ("H").charCodeAt(0) & 0xFF;
|
||||
var underScore = ("_").charCodeAt(0) & 0xFF;
|
||||
var five = ("5").charCodeAt(0) & 0xFF;
|
||||
var one = ("1").charCodeAt(0) & 0xFF;
|
||||
var two = ("2").charCodeAt(0) & 0xFF;
|
||||
var M = ("M").charCodeAt(0) & 0xFF;
|
||||
var V = ("V").charCodeAt(0) & 0xFF;
|
||||
var length = ((this.ROM.length | 0) - 12) | 0;
|
||||
for (var index = 0; (index | 0) < (length | 0); index = ((index | 0) + 4) | 0) {
|
||||
if ((this.ROM[index | 0] | 0) == (F | 0)) {
|
||||
if ((this.ROM[index | 1] | 0) == (L | 0)) {
|
||||
if ((this.ROM[index | 2] | 0) == (A | 0)) {
|
||||
if ((this.ROM[index | 3] | 0) == (S | 0)) {
|
||||
var tempIndex = ((index | 0) + 4) | 0;
|
||||
if ((this.ROM[tempIndex | 0] | 0) == (H | 0)) {
|
||||
if ((this.ROM[tempIndex | 1] | 0) == (underScore | 0)) {
|
||||
if ((this.ROM[tempIndex | 2] | 0) == (V | 0)) {
|
||||
flash_types |= 1;
|
||||
}
|
||||
}
|
||||
else if ((this.ROM[tempIndex | 1] | 0) == (five | 0)) {
|
||||
if ((this.ROM[tempIndex | 2] | 0) == (one | 0)) {
|
||||
if ((this.ROM[tempIndex | 3] | 0) == (two | 0)) {
|
||||
tempIndex = ((tempIndex | 0) + 4) | 0;
|
||||
if ((this.ROM[tempIndex | 0] | 0) == (underScore | 0)) {
|
||||
if ((this.ROM[tempIndex | 1] | 0) == (V | 0)) {
|
||||
flash_types |= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((this.ROM[tempIndex | 1] | 0) == (one | 0)) {
|
||||
if ((this.ROM[tempIndex | 2] | 0) == (M | 0)) {
|
||||
if ((this.ROM[tempIndex | 3] | 0) == (underScore | 0)) {
|
||||
tempIndex = ((tempIndex | 0) + 4) | 0;
|
||||
if ((this.ROM[tempIndex | 0] | 0) == (V | 0)) {
|
||||
flash_types |= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.flash_is128 = ((flash_types | 0) >= 4);
|
||||
this.flash_isAtmel = ((flash_types | 0) <= 1);
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.readROMOnly8 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) < (this.ROMLength | 0)) {
|
||||
data = this.ROM[address & 0x1FFFFFF] | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
if (__LITTLE_ENDIAN__) {
|
||||
GameBoyAdvanceCartridge.prototype.readROMOnly16 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) < (this.ROMLength | 0)) {
|
||||
data = this.ROM16[(address >> 1) & 0xFFFFFF] | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.readROMOnly32 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) < (this.ROMLength | 0)) {
|
||||
data = this.ROM32[(address >> 2) & 0x7FFFFF] | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameBoyAdvanceCartridge.prototype.readROMOnly16 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) < (this.ROMLength | 0)) {
|
||||
data = this.ROM[address] | (this.ROM[address | 1] << 8);
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.readROMOnly32 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) < (this.ROMLength | 0)) {
|
||||
data = this.ROM[address] | (this.ROM[address | 1] << 8) | (this.ROM[address | 2] << 16) | (this.ROM[address | 3] << 24);
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.readROM8 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) > 0xC9) {
|
||||
//Definitely ROM:
|
||||
data = this.readROMOnly8(address | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Possibly GPIO:
|
||||
data = this.IOCore.saves.readGPIO8(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.readROM16 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) > 0xC9) {
|
||||
//Definitely ROM:
|
||||
data = this.readROMOnly16(address | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Possibly GPIO:
|
||||
data = this.IOCore.saves.readGPIO16(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.readROM32 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) > 0xC9) {
|
||||
//Definitely ROM:
|
||||
data = this.readROMOnly32(address | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Possibly GPIO:
|
||||
data = this.IOCore.saves.readGPIO32(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.readROM8Space2 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) >= 0xC4 && (address | 0) < 0xCA) {
|
||||
//Possibly GPIO:
|
||||
data = this.IOCore.saves.readGPIO8(address | 0) | 0;
|
||||
}
|
||||
else if ((address | 0) >= (this.EEPROMStart | 0)) {
|
||||
//Possibly EEPROM:
|
||||
data = this.IOCore.saves.readEEPROM8(address | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Definitely ROM:
|
||||
data = this.readROMOnly8(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.readROM16Space2 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) >= 0xC4 && (address | 0) < 0xCA) {
|
||||
//Possibly GPIO:
|
||||
data = this.IOCore.saves.readGPIO16(address | 0) | 0;
|
||||
}
|
||||
else if ((address | 0) >= (this.EEPROMStart | 0)) {
|
||||
//Possibly EEPROM:
|
||||
data = this.IOCore.saves.readEEPROM16(address | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Definitely ROM:
|
||||
data = this.readROMOnly16(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.readROM32Space2 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) >= 0xC4 && (address | 0) < 0xCA) {
|
||||
//Possibly GPIO:
|
||||
data = this.IOCore.saves.readGPIO32(address | 0) | 0;
|
||||
}
|
||||
else if ((address | 0) >= (this.EEPROMStart | 0)) {
|
||||
//Possibly EEPROM:
|
||||
data = this.IOCore.saves.readEEPROM32(address | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Definitely ROM:
|
||||
data = this.readROMOnly32(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.writeROM8 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((address | 0) >= 0xC4 && (address | 0) < 0xCA) {
|
||||
//GPIO Chip (RTC):
|
||||
this.IOCore.saves.writeGPIO8(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.writeROM16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((address | 0) >= 0xC4 && (address | 0) < 0xCA) {
|
||||
//GPIO Chip (RTC):
|
||||
this.IOCore.saves.writeGPIO16(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.writeROM16DMA = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((address | 0) >= 0xC4 && (address | 0) < 0xCA) {
|
||||
//GPIO Chip (RTC):
|
||||
this.IOCore.saves.writeGPIO16(address | 0, data | 0);
|
||||
}
|
||||
else if ((address | 0) >= (this.EEPROMStart | 0)) {
|
||||
//Possibly EEPROM:
|
||||
this.IOCore.saves.writeEEPROM16(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.writeROM32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((address | 0) >= 0xC4 && (address | 0) < 0xCA) {
|
||||
//GPIO Chip (RTC):
|
||||
this.IOCore.saves.writeGPIO32(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceCartridge.prototype.nextIRQEventTime = function () {
|
||||
//Nothing yet implement that would fire an IRQ:
|
||||
return 0x7FFFFFFF;
|
||||
}
|
98
public/gfiles/gba/IodineGBA/core/DMA.js
Normal file
98
public/gfiles/gba/IodineGBA/core/DMA.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceDMA(IOCore) {
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.initialize = function () {
|
||||
this.dmaChannel0 = this.IOCore.dmaChannel0;
|
||||
this.dmaChannel1 = this.IOCore.dmaChannel1;
|
||||
this.dmaChannel2 = this.IOCore.dmaChannel2;
|
||||
this.dmaChannel3 = this.IOCore.dmaChannel3;
|
||||
this.currentMatch = -1;
|
||||
this.fetch = 0;
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.getCurrentFetchValue = function () {
|
||||
return this.fetch | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.gfxHBlankRequest = function () {
|
||||
//Pass H-Blank signal to all DMA channels:
|
||||
this.requestDMA(0x4);
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.gfxVBlankRequest = function () {
|
||||
//Pass V-Blank signal to all DMA channels:
|
||||
this.requestDMA(0x2);
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.requestDMA = function (DMAType) {
|
||||
DMAType = DMAType | 0;
|
||||
this.dmaChannel0.requestDMA(DMAType | 0);
|
||||
this.dmaChannel1.requestDMA(DMAType | 0);
|
||||
this.dmaChannel2.requestDMA(DMAType | 0);
|
||||
this.dmaChannel3.requestDMA(DMAType | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.findLowestDMA = function () {
|
||||
if ((this.dmaChannel0.getMatchStatus() | 0) != 0) {
|
||||
return 0;
|
||||
}
|
||||
if ((this.dmaChannel1.getMatchStatus() | 0) != 0) {
|
||||
return 1;
|
||||
}
|
||||
if ((this.dmaChannel2.getMatchStatus() | 0) != 0) {
|
||||
return 2;
|
||||
}
|
||||
if ((this.dmaChannel3.getMatchStatus() | 0) != 0) {
|
||||
return 3;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.update = function () {
|
||||
var lowestDMAFound = this.findLowestDMA();
|
||||
if ((lowestDMAFound | 0) < 4) {
|
||||
//Found an active DMA:
|
||||
if ((this.currentMatch | 0) == -1) {
|
||||
this.IOCore.flagDMA();
|
||||
}
|
||||
if ((this.currentMatch | 0) != (lowestDMAFound | 0)) {
|
||||
//Re-broadcasting on address bus, so non-seq:
|
||||
this.IOCore.wait.NonSequentialBroadcast();
|
||||
this.currentMatch = lowestDMAFound | 0;
|
||||
}
|
||||
}
|
||||
else if ((this.currentMatch | 0) != -1) {
|
||||
//No active DMA found:
|
||||
this.currentMatch = -1;
|
||||
this.IOCore.deflagDMA();
|
||||
this.IOCore.updateCoreSpill();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.perform = function () {
|
||||
//Call the correct channel to process:
|
||||
switch (this.currentMatch | 0) {
|
||||
case 0:
|
||||
this.dmaChannel0.handleDMACopy();
|
||||
break;
|
||||
case 1:
|
||||
this.dmaChannel1.handleDMACopy();
|
||||
break;
|
||||
case 2:
|
||||
this.dmaChannel2.handleDMACopy();
|
||||
break;
|
||||
default:
|
||||
this.dmaChannel3.handleDMACopy();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.updateFetch = function (data) {
|
||||
data = data | 0;
|
||||
this.fetch = data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA.prototype.nextEventTime = function () {
|
||||
var clocks = Math.min(this.dmaChannel0.nextEventTime() | 0, this.dmaChannel1.nextEventTime() | 0, this.dmaChannel2.nextEventTime() | 0, this.dmaChannel3.nextEventTime() | 0) | 0;
|
||||
return clocks | 0;
|
||||
}
|
469
public/gfiles/gba/IodineGBA/core/Emulator.js
Normal file
469
public/gfiles/gba/IodineGBA/core/Emulator.js
Normal file
|
@ -0,0 +1,469 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2019 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceEmulator() {
|
||||
this.settings = {
|
||||
SKIPBoot:false, //Skip the BIOS boot screen.
|
||||
audioBufferUnderrunLimit:100, //Audio buffer minimum span amount over x milliseconds.
|
||||
audioBufferDynamicLimit:32, //Audio buffer dynamic minimum span amount over x milliseconds.
|
||||
audioBufferSize:300, //Audio buffer maximum span amount over x milliseconds.
|
||||
emulatorSpeed:1.0, //Speed multiplier of the emulator.
|
||||
metricCollectionMinimum:500, //How many milliseconds of cycling to count before determining speed.
|
||||
dynamicSpeed:false, //Whether to actively change the target speed for best user experience.
|
||||
overclockBlockLimit:200, //Whether to throttle clocks in audio adjustment.
|
||||
offthreadGfxEnabled:true //Whether to allow offthread graphics rendering if support is present.
|
||||
};
|
||||
this.audioFound = 0; //Do we have audio output sink found yet?
|
||||
this.emulatorStatus = 0x10; //{paused, saves loaded, fault found, loaded}
|
||||
this.BIOS = []; //Initialize BIOS as not existing.
|
||||
this.ROM = []; //Initialize BIOS as not existing.
|
||||
this.audioUpdateState = 1; //Do we need to update the sound core with new info?
|
||||
this.saveExportHandler = null; //Save export handler attached by GUI.
|
||||
this.saveImportHandler = null; //Save import handler attached by GUI.
|
||||
this.speedCallback = null; //Speed report handler attached by GUI.
|
||||
this.playStatusCallback = null; //Play status change handler attached by GUI.
|
||||
this.startCallbacks = []; //Some jobs to run at iteration head.
|
||||
this.endCallbacks = []; //Some jobs to run at iteration end.
|
||||
this.terminationCallbacks = []; //Some jobs to run if the emulation core is killed.
|
||||
this.timerIntervalRate = 16; //How often the emulator core is called into (in milliseconds).
|
||||
this.lastTimestamp = 0; //Track the last time given in milliseconds.
|
||||
this.dynamicSpeedRefresh = false; //Whether speed is allowed to be changed dynamically in the current cycle.
|
||||
this.calculateTimings(); //Calculate some multipliers against the core emulator timer.
|
||||
this.generateCoreExposed(); //Generate a limit API for the core to call this shell object.
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.generateCoreExposed = function () {
|
||||
var parentObj = this;
|
||||
this.coreExposed = {
|
||||
outputAudio:function (l, r) {
|
||||
parentObj.outputAudio(l, r);
|
||||
},
|
||||
graphicsHandle:null,
|
||||
appendStartIterationSync:function (callback) {
|
||||
parentObj.startCallbacks.push(callback);
|
||||
},
|
||||
appendEndIterationSync:function (callback) {
|
||||
parentObj.endCallbacks.push(callback);
|
||||
},
|
||||
appendTerminationSync:function (callback) {
|
||||
parentObj.terminationCallbacks.push(callback);
|
||||
},
|
||||
offthreadGfxEnabled:function () {
|
||||
return !!parentObj.settings.offthreadGfxEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.play = function () {
|
||||
if ((this.emulatorStatus | 0) >= 0x10) {
|
||||
this.emulatorStatus = this.emulatorStatus & 0xF;
|
||||
if ((this.emulatorStatus & 0x1) == 0 && this.BIOS && this.ROM) {
|
||||
if ((this.initializeCore() | 0) == 0) {
|
||||
//Failure to initialize:
|
||||
this.pause();
|
||||
return;
|
||||
}
|
||||
this.importSave();
|
||||
}
|
||||
this.invalidateMetrics();
|
||||
this.setBufferSpace();
|
||||
//Report new status back:
|
||||
this.playStatusCallback(1);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.pause = function () {
|
||||
if ((this.emulatorStatus | 0) < 0x10) {
|
||||
this.exportSave();
|
||||
this.emulatorStatus = this.emulatorStatus | 0x10;
|
||||
//Report new status back:
|
||||
this.playStatusCallback(0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.stop = function () {
|
||||
this.emulatorStatus = this.emulatorStatus & 0x1C;
|
||||
this.audioUpdateState = 1;
|
||||
this.pause();
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.restart = function () {
|
||||
if ((this.emulatorStatus & 0x1) == 0x1) {
|
||||
this.emulatorStatus = this.emulatorStatus & 0x1D;
|
||||
this.exportSave();
|
||||
if ((this.initializeCore() | 0) == 0) {
|
||||
//Failure to initialize:
|
||||
this.pause();
|
||||
return;
|
||||
}
|
||||
this.importSave();
|
||||
this.audioUpdateState = 1;
|
||||
this.processNewSpeed(1);
|
||||
this.setBufferSpace();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.timerCallback = function (lastTimestamp) {
|
||||
//Callback passes us a reference timestamp:
|
||||
this.lastTimestamp = lastTimestamp >>> 0;
|
||||
switch (this.emulatorStatus | 0) {
|
||||
//Core initialized and saves loaded:
|
||||
case 5:
|
||||
this.iterationStartSequence(); //Run start of iteration stuff.
|
||||
this.IOCore.enter(this.CPUCyclesTotal | 0); //Step through the emulation core loop.
|
||||
this.iterationEndSequence(); //Run end of iteration stuff.
|
||||
break;
|
||||
//Core initialized, but saves still loading:
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
//Some pending error is preventing execution, so pause:
|
||||
this.pause();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.iterationStartSequence = function () {
|
||||
this.calculateSpeedPercentage(); //Calculate the emulator realtime run speed heuristics.
|
||||
this.emulatorStatus = this.emulatorStatus | 0x2; //If the end routine doesn't unset this, then we are marked as having crashed.
|
||||
this.audioUnderrunAdjustment(); //If audio is enabled, look to see how much we should overclock by to maintain the audio buffer.
|
||||
this.audioPushNewState(); //Check to see if we need to update the audio core for any output changes.
|
||||
this.runStartJobs(); //Run various callbacks assigned from internal components.
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.iterationEndSequence = function () {
|
||||
this.emulatorStatus = this.emulatorStatus & 0x1D; //If core did not throw while running, unset the fatal error flag.
|
||||
this.clockCyclesSinceStart = ((this.clockCyclesSinceStart | 0) + (this.CPUCyclesTotal | 0)) | 0; //Accumulate tracking.
|
||||
this.submitAudioBuffer(); //Flush audio buffer to output.
|
||||
this.runEndJobs(); //Run various callbacks assigned from internal components.
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.runStartJobs = function () {
|
||||
var length = this.startCallbacks.length | 0;
|
||||
//Loop through all jobs:
|
||||
for (var index = 0; (index | 0) < (length | 0); index = ((index | 0) + 1) | 0) {
|
||||
//Run job:
|
||||
this.startCallbacks[index | 0]();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.runEndJobs = function () {
|
||||
var length = this.endCallbacks.length | 0;
|
||||
//Loop through all jobs:
|
||||
for (var index = 0; (index | 0) < (length | 0); index = ((index | 0) + 1) | 0) {
|
||||
//Run job:
|
||||
this.endCallbacks[index | 0]();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.runTerminationJobs = function () {
|
||||
var length = this.terminationCallbacks.length | 0;
|
||||
//Loop through all jobs:
|
||||
for (var index = 0; (index | 0) < (length | 0); index = ((index | 0) + 1) | 0) {
|
||||
//Run job:
|
||||
this.terminationCallbacks[index | 0]();
|
||||
}
|
||||
//Remove old jobs:
|
||||
this.startCallbacks = [];
|
||||
this.endCallbacks = [];
|
||||
this.terminationCallbacks = [];
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.attachROM = function (ROM) {
|
||||
this.stop();
|
||||
this.ROM = ROM;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.attachBIOS = function (BIOS) {
|
||||
this.stop();
|
||||
this.BIOS = BIOS;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.getGameName = function () {
|
||||
if ((this.emulatorStatus & 0x3) == 0x1) {
|
||||
return this.IOCore.cartridge.name;
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.attachSaveExportHandler = function (handler) {
|
||||
if (typeof handler == "function") {
|
||||
this.saveExportHandler = handler;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.attachSaveImportHandler = function (handler) {
|
||||
if (typeof handler == "function") {
|
||||
this.saveImportHandler = handler;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.attachSpeedHandler = function (handler) {
|
||||
if (typeof handler == "function") {
|
||||
this.speedCallback = handler;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.attachPlayStatusHandler = function (handler) {
|
||||
if (typeof handler == "function") {
|
||||
this.playStatusCallback = handler;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.importSave = function () {
|
||||
if (this.saveImportHandler) {
|
||||
var name = this.getGameName();
|
||||
if (name != "") {
|
||||
var parentObj = this;
|
||||
this.emulatorStatus = this.emulatorStatus & 0x1B;
|
||||
this.saveImportHandler(name, function (save) {
|
||||
parentObj.emulatorStatus = parentObj.emulatorStatus & 0x1B;
|
||||
parentObj.saveImportHandler("TYPE_" + name, function (saveType) {
|
||||
if (save && saveType && (parentObj.emulatorStatus & 0x3) == 0x1) {
|
||||
var length = save.length | 0;
|
||||
var convertedSave = getUint8Array(length | 0);
|
||||
if ((length | 0) > 0) {
|
||||
for (var index = 0; (index | 0) < (length | 0); index = ((index | 0) + 1) | 0) {
|
||||
convertedSave[index | 0] = save[index | 0] & 0xFF;
|
||||
}
|
||||
//We used to save this code wrong, fix the error in old saves:
|
||||
if ((saveType.length | 0) != 1) {
|
||||
//0 is fallthrough "UNKNOWN" aka autodetect type:
|
||||
parentObj.IOCore.saves.importSave(convertedSave, 0);
|
||||
}
|
||||
else {
|
||||
parentObj.IOCore.saves.importSave(convertedSave, saveType[0] & 0xFF);
|
||||
}
|
||||
parentObj.emulatorStatus = parentObj.emulatorStatus | 0x4;
|
||||
}
|
||||
}
|
||||
}, function (){parentObj.emulatorStatus = parentObj.emulatorStatus | 0x4;});
|
||||
}, function (){parentObj.emulatorStatus = parentObj.emulatorStatus | 0x4;});
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.emulatorStatus = this.emulatorStatus | 0x4;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.exportSave = function () {
|
||||
if (this.saveExportHandler && (this.emulatorStatus & 0x3) == 0x1) {
|
||||
var save = this.IOCore.saves.exportSave();
|
||||
var saveType = this.IOCore.saves.exportSaveType() | 0;
|
||||
if (save != null) {
|
||||
this.saveExportHandler(this.IOCore.cartridge.name, save);
|
||||
this.saveExportHandler("TYPE_" + this.IOCore.cartridge.name, [saveType | 0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.setSpeed = function (speed) {
|
||||
speed = +speed;
|
||||
//Dynamic Speed overrides custom speed levels:
|
||||
if (!this.settings.dynamicSpeed) {
|
||||
this.processNewSpeed(+speed);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.processNewSpeed = function (speed) {
|
||||
speed = +speed;
|
||||
//0.003 for the integer resampler limitations, 0x3F for int math limitations:
|
||||
speed = +Math.min(Math.max(+speed, 0.003), 0x3F);
|
||||
if ((+speed) != (+this.settings.emulatorSpeed)) {
|
||||
this.settings.emulatorSpeed = +speed;
|
||||
this.calculateTimings();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.incrementSpeed = function (delta) {
|
||||
delta = +delta;
|
||||
this.setSpeed((+delta) + (+this.settings.emulatorSpeed));
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.getSpeed = function () {
|
||||
return +this.settings.emulatorSpeed;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.invalidateMetrics = function () {
|
||||
this.clockCyclesSinceStart = 0;
|
||||
this.metricStart = 0;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.resetMetrics = function () {
|
||||
this.clockCyclesSinceStart = 0;
|
||||
this.metricStart = this.lastTimestamp >>> 0;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.calculateTimings = function () {
|
||||
this.clocksPerSecond = Math.min((+this.settings.emulatorSpeed) * 0x1000000, 0x3F000000) | 0;
|
||||
this.clocksPerMilliSecond = +((this.clocksPerSecond | 0) / 1000);
|
||||
this.CPUCyclesPerIteration = ((+this.clocksPerMilliSecond) * (+this.timerIntervalRate)) | 0;
|
||||
this.CPUCyclesTotal = this.CPUCyclesPerIteration | 0;
|
||||
this.initializeAudioLogic();
|
||||
this.reinitializeAudio();
|
||||
this.invalidateMetrics();
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.setIntervalRate = function (intervalRate) {
|
||||
intervalRate = +intervalRate;
|
||||
if ((+intervalRate) > 0 && (+intervalRate) < 1000) {
|
||||
if ((+intervalRate) != (+this.timerIntervalRate)) {
|
||||
this.timerIntervalRate = +intervalRate;
|
||||
this.calculateTimings();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.calculateSpeedPercentage = function () {
|
||||
if ((this.metricStart >>> 0) != 0) {
|
||||
var timeDiff = Math.max(((this.lastTimestamp >>> 0) - (this.metricStart >>> 0)) | 0, 1) >>> 0;
|
||||
if ((timeDiff >>> 0) >= (this.settings.metricCollectionMinimum | 0)) {
|
||||
if (this.speedCallback) {
|
||||
var result = ((this.clockCyclesSinceStart | 0) * 100000) / ((timeDiff >>> 0) * 0x1000000);
|
||||
this.speedCallback(+result);
|
||||
}
|
||||
//Reset counter for speed check:
|
||||
this.resetMetrics();
|
||||
//Do a computation for dynamic speed this iteration:
|
||||
this.dynamicSpeedRefresh = true;
|
||||
}
|
||||
else {
|
||||
//Postpone any dynamic speed changes this iteration:
|
||||
this.dynamicSpeedRefresh = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Reset counter for speed check:
|
||||
this.resetMetrics();
|
||||
//Postpone any dynamic speed changes this iteration:
|
||||
this.dynamicSpeedRefresh = false;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.initializeCore = function () {
|
||||
//Wrap up any old internal instance callbacks:
|
||||
this.runTerminationJobs();
|
||||
//Setup a new instance of the i/o core:
|
||||
this.IOCore = new GameBoyAdvanceIO(this.settings.SKIPBoot, this.coreExposed, this.BIOS, this.ROM);
|
||||
//Call the initalization procedure and get status code:
|
||||
var allowInit = this.IOCore.initialize() | 0;
|
||||
//Append status code as play status flag for emulator runtime:
|
||||
this.emulatorStatus = this.emulatorStatus | allowInit;
|
||||
return allowInit | 0;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.keyDown = function (keyPressed) {
|
||||
keyPressed = keyPressed | 0;
|
||||
if ((this.emulatorStatus | 0) < 0x10 && (keyPressed | 0) >= 0 && (keyPressed | 0) <= 9) {
|
||||
this.IOCore.joypad.keyPress(keyPressed | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.keyUp = function (keyReleased) {
|
||||
keyReleased = keyReleased | 0;
|
||||
if ((this.emulatorStatus | 0) < 0x10 && (keyReleased | 0) >= 0 && (keyReleased | 0) <= 9) {
|
||||
this.IOCore.joypad.keyRelease(keyReleased | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.attachGraphicsFrameHandler = function (handler) {
|
||||
if (typeof handler == "object") {
|
||||
this.coreExposed.graphicsHandle = handler;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.attachAudioHandler = function (mixerInputHandler) {
|
||||
if (mixerInputHandler) {
|
||||
this.audio = mixerInputHandler;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.enableAudio = function () {
|
||||
if ((this.audioFound | 0) == 0 && this.audio) {
|
||||
this.audioFound = 1; //Set audio to 'found' by default.
|
||||
//Attempt to enable audio:
|
||||
var parentObj = this;
|
||||
this.audio.initialize(2, (this.clocksPerSecond | 0) / (this.audioResamplerFirstPassFactor | 0), Math.max((+this.clocksPerMilliSecond) * (this.settings.audioBufferSize | 0) / (this.audioResamplerFirstPassFactor | 0), 4) | 0, function () {
|
||||
//Not needed
|
||||
}, function () {
|
||||
//We manually check at the start of each timer interval, so not needed here.
|
||||
}, function () {
|
||||
//Disable audio in the callback here:
|
||||
parentObj.disableAudio();
|
||||
});
|
||||
this.audio.register();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.disableAudio = function () {
|
||||
if ((this.audioFound | 0) != 0) {
|
||||
this.audio.unregister();
|
||||
this.audioFound = 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.reinitializeAudio = function () {
|
||||
if ((this.audioFound | 0) != 0) {
|
||||
this.disableAudio();
|
||||
this.enableAudio();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.initializeAudioLogic = function () {
|
||||
//Calculate the variables for the preliminary downsampler first:
|
||||
this.audioResamplerFirstPassFactor = Math.min(Math.floor((this.clocksPerSecond | 0) / 44100), Math.floor(0x7FFFFFFF / 0x3FF)) | 0;
|
||||
this.audioDownSampleInputDivider = +((2 / 0x3FF) / (this.audioResamplerFirstPassFactor | 0));
|
||||
this.initializeAudioBuffering();
|
||||
//Need to push the new resample factor:
|
||||
this.audioUpdateState = 1;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.initializeAudioBuffering = function () {
|
||||
this.audioDestinationPosition = 0;
|
||||
this.audioBufferContainAmount = Math.max((+this.clocksPerMilliSecond) * (this.settings.audioBufferUnderrunLimit | 0) / (this.audioResamplerFirstPassFactor | 0), 3) << 1;
|
||||
this.audioBufferOverclockBlockAmount = Math.max((+this.clocksPerMilliSecond) * (this.settings.overclockBlockLimit | 0) / (this.audioResamplerFirstPassFactor | 0), 3) << 1;
|
||||
this.audioBufferDynamicContainAmount = Math.max((+this.clocksPerMilliSecond) * (this.settings.audioBufferDynamicLimit | 0) / (this.audioResamplerFirstPassFactor | 0), 2) << 1;
|
||||
//Underrun logic will request at most 32 milliseconds of runtime per iteration, so set buffer size to 64 ms:
|
||||
var audioNumSamplesTotal = Math.max(((+this.clocksPerMilliSecond) / (this.audioResamplerFirstPassFactor | 0)) << 6, 4) << 1;
|
||||
if (!this.audioBuffer || ((audioNumSamplesTotal | 0) > (this.audioBuffer.length | 0))) {
|
||||
//Only regen buffer if the size is increased:
|
||||
this.audioBuffer = getFloat32Array(audioNumSamplesTotal | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.outputAudio = function (downsampleInputLeft, downsampleInputRight) {
|
||||
downsampleInputLeft = downsampleInputLeft | 0;
|
||||
downsampleInputRight = downsampleInputRight | 0;
|
||||
this.audioBuffer[this.audioDestinationPosition | 0] = ((downsampleInputLeft | 0) * (+this.audioDownSampleInputDivider)) - 1;
|
||||
this.audioDestinationPosition = ((this.audioDestinationPosition | 0) + 1) | 0;
|
||||
this.audioBuffer[this.audioDestinationPosition | 0] = ((downsampleInputRight | 0) * (+this.audioDownSampleInputDivider)) - 1;
|
||||
this.audioDestinationPosition = ((this.audioDestinationPosition | 0) + 1) | 0;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.submitAudioBuffer = function () {
|
||||
if ((this.audioFound | 0) != 0) {
|
||||
this.audio.push(this.audioBuffer, 0, this.audioDestinationPosition | 0);
|
||||
}
|
||||
this.audioDestinationPosition = 0;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.audioUnderrunAdjustment = function () {
|
||||
this.CPUCyclesTotal = this.CPUCyclesPerIteration | 0;
|
||||
if ((this.audioFound | 0) != 0) {
|
||||
var remainingAmount = this.audio.remainingBuffer();
|
||||
if (typeof remainingAmount == "number") {
|
||||
remainingAmount = Math.max(remainingAmount | 0, 0) | 0;
|
||||
var underrunAmount = ((this.audioBufferContainAmount | 0) - (remainingAmount | 0)) | 0;
|
||||
if ((underrunAmount | 0) > 0) {
|
||||
if (this.dynamicSpeedRefresh && this.settings.dynamicSpeed) {
|
||||
if (((this.audioBufferDynamicContainAmount | 0) - (remainingAmount | 0)) > 0) {
|
||||
var speed = +this.getSpeed();
|
||||
speed = Math.max((+speed) - 0.1, 0.003);
|
||||
this.processNewSpeed(+speed);
|
||||
}
|
||||
}
|
||||
this.CPUCyclesTotal = Math.min(((this.CPUCyclesTotal | 0) + ((underrunAmount >> 1) * (this.audioResamplerFirstPassFactor | 0))) | 0, (+this.clocksPerMilliSecond) << 5) | 0;
|
||||
}
|
||||
else {
|
||||
if (this.dynamicSpeedRefresh && this.settings.dynamicSpeed) {
|
||||
var speed = +this.getSpeed();
|
||||
if ((+speed) < 1) {
|
||||
speed = +Math.min((+speed) + 0.01, 1);
|
||||
this.processNewSpeed(+speed);
|
||||
}
|
||||
}
|
||||
var overrunAmount = ((remainingAmount | 0) - (this.audioBufferOverclockBlockAmount | 0)) | 0;
|
||||
if ((overrunAmount | 0) > 0) {
|
||||
this.CPUCyclesTotal = Math.max(((this.CPUCyclesTotal | 0) - ((overrunAmount >> 1) * (this.audioResamplerFirstPassFactor | 0))) | 0, 0) | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.audioPushNewState = function () {
|
||||
if ((this.audioUpdateState | 0) != 0) {
|
||||
this.IOCore.sound.initializeOutput(this.audioResamplerFirstPassFactor | 0);
|
||||
this.audioUpdateState = 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.setBufferSpace = function () {
|
||||
if ((this.audioFound | 0) != 0) {
|
||||
//Fill the audio system with zeros for buffer stabilization on start:
|
||||
this.audio.setBufferSpace(this.audioBufferContainAmount | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.toggleSkipBootROM = function (SKIPBoot) {
|
||||
this.settings.SKIPBoot = !!SKIPBoot;
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.toggleDynamicSpeed = function (dynamicSpeed) {
|
||||
this.settings.dynamicSpeed = !!dynamicSpeed;
|
||||
this.processNewSpeed(1);
|
||||
}
|
||||
GameBoyAdvanceEmulator.prototype.toggleOffthreadGraphics = function (offthreadGfxEnabled) {
|
||||
this.settings.offthreadGfxEnabled = !!offthreadGfxEnabled;
|
||||
}
|
304
public/gfiles/gba/IodineGBA/core/Graphics.js
Normal file
304
public/gfiles/gba/IodineGBA/core/Graphics.js
Normal file
|
@ -0,0 +1,304 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceGraphics(IOCore) {
|
||||
//Build references:
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.initialize = function () {
|
||||
this.gfxRenderer = this.IOCore.gfxRenderer;
|
||||
this.dma = this.IOCore.dma;
|
||||
this.dmaChannel3 = this.IOCore.dmaChannel3;
|
||||
this.irq = this.IOCore.irq;
|
||||
this.wait = this.IOCore.wait;
|
||||
this.initializeState();
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.initializeState = function () {
|
||||
//Initialize Pre-Boot:
|
||||
this.renderedScanLine = false;
|
||||
this.statusFlags = 0;
|
||||
this.IRQFlags = 0;
|
||||
this.VCounter = 0;
|
||||
this.currentScanLine = 0;
|
||||
this.LCDTicks = 0;
|
||||
if (this.IOCore.SKIPBoot) {
|
||||
//BIOS entered the ROM at line 0x7C:
|
||||
this.currentScanLine = 0x7C;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.addClocks = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
//Call this when clocking the state some more:
|
||||
this.LCDTicks = ((this.LCDTicks | 0) + (clocks | 0)) | 0;
|
||||
this.clockLCDState();
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.clockLCDState = function () {
|
||||
if ((this.LCDTicks | 0) >= 960) {
|
||||
this.clockScanLine(); //Line finishes drawing at clock 960.
|
||||
this.clockLCDStatePostRender(); //Check for hblank and clocking into next line.
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.clockScanLine = function () {
|
||||
if (!this.renderedScanLine) { //If we rendered the scanline, don't run this again.
|
||||
this.renderedScanLine = true; //Mark rendering.
|
||||
if ((this.currentScanLine | 0) < 160) {
|
||||
this.gfxRenderer.incrementScanLineQueue(); //Tell the gfx JIT to queue another line to draw.
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.clockLCDStatePostRender = function () {
|
||||
if ((this.LCDTicks | 0) >= 1006) {
|
||||
//HBlank Event Occurred:
|
||||
this.updateHBlank();
|
||||
if ((this.LCDTicks | 0) >= 1232) {
|
||||
//Clocking to next line occurred:
|
||||
this.clockLCDNextLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.clockLCDNextLine = function () {
|
||||
/*We've now overflowed the LCD scan line state machine counter,
|
||||
which tells us we need to be on a new scan-line and refresh over.*/
|
||||
this.renderedScanLine = false; //Unmark line render.
|
||||
this.statusFlags = this.statusFlags & 0x5; //Un-mark HBlank.
|
||||
//De-clock for starting on new scan-line:
|
||||
this.LCDTicks = ((this.LCDTicks | 0) - 1232) | 0; //We start out at the beginning of the next line.
|
||||
//Increment scanline counter:
|
||||
this.currentScanLine = ((this.currentScanLine | 0) + 1) | 0; //Increment to the next scan line.
|
||||
//Handle switching in/out of vblank:
|
||||
if ((this.currentScanLine | 0) >= 160) {
|
||||
//Handle special case scan lines of vblank:
|
||||
switch (this.currentScanLine | 0) {
|
||||
case 160:
|
||||
this.updateVBlankStart(); //Update state for start of vblank.
|
||||
case 161:
|
||||
this.dmaChannel3.gfxDisplaySyncRequest(); //Display Sync. DMA trigger.
|
||||
break;
|
||||
case 162:
|
||||
this.dmaChannel3.gfxDisplaySyncEnableCheck(); //Display Sync. DMA reset on start of line 162.
|
||||
break;
|
||||
case 227:
|
||||
this.statusFlags = this.statusFlags & 0x6; //Un-mark VBlank on start of last vblank line.
|
||||
break;
|
||||
case 228:
|
||||
this.currentScanLine = 0; //Reset scan-line to zero (First line of draw).
|
||||
}
|
||||
}
|
||||
else if ((this.currentScanLine | 0) > 1) {
|
||||
this.dmaChannel3.gfxDisplaySyncRequest(); //Display Sync. DMA trigger.
|
||||
}
|
||||
this.checkVCounter(); //We're on a new scan line, so check the VCounter for match.
|
||||
this.isRenderingCheckPreprocess(); //Update a check value.
|
||||
//Recursive clocking of the LCD state:
|
||||
this.clockLCDState();
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.updateHBlank = function () {
|
||||
if ((this.statusFlags & 0x2) == 0) { //If we were last in HBlank, don't run this again.
|
||||
this.statusFlags = this.statusFlags | 0x2; //Mark HBlank.
|
||||
if ((this.IRQFlags & 0x10) != 0) {
|
||||
this.irq.requestIRQ(0x2); //Check for IRQ.
|
||||
}
|
||||
if ((this.currentScanLine | 0) < 160) {
|
||||
this.dma.gfxHBlankRequest(); //Check for HDMA Trigger.
|
||||
}
|
||||
this.isRenderingCheckPreprocess(); //Update a check value.
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.checkVCounter = function () {
|
||||
if ((this.currentScanLine | 0) == (this.VCounter | 0)) { //Check for VCounter match.
|
||||
this.statusFlags = this.statusFlags | 0x4;
|
||||
if ((this.IRQFlags & 0x20) != 0) { //Check for VCounter IRQ.
|
||||
this.irq.requestIRQ(0x4);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.statusFlags = this.statusFlags & 0x3;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.nextVBlankIRQEventTime = function () {
|
||||
var nextEventTime = 0x7FFFFFFF;
|
||||
if ((this.IRQFlags & 0x8) != 0) {
|
||||
//Only give a time if we're allowed to irq:
|
||||
nextEventTime = this.nextVBlankEventTime() | 0;
|
||||
}
|
||||
return nextEventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.nextHBlankEventTime = function () {
|
||||
var time = this.LCDTicks | 0;
|
||||
if ((time | 0) < 1006) {
|
||||
//Haven't reached hblank yet, so hblank offset - current:
|
||||
time = (1006 - (time | 0)) | 0;
|
||||
}
|
||||
else {
|
||||
//We're in hblank, so it's end clock - current + next scanline hblank offset:
|
||||
time = (2238 - (time | 0)) | 0;
|
||||
}
|
||||
return time | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.nextHBlankIRQEventTime = function () {
|
||||
var nextEventTime = 0x7FFFFFFF;
|
||||
if ((this.IRQFlags & 0x10) != 0) {
|
||||
//Only give a time if we're allowed to irq:
|
||||
nextEventTime = this.nextHBlankEventTime() | 0;
|
||||
}
|
||||
return nextEventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.nextVCounterIRQEventTime = function () {
|
||||
var nextEventTime = 0x7FFFFFFF;
|
||||
if ((this.IRQFlags & 0x20) != 0) {
|
||||
//Only give a time if we're allowed to irq:
|
||||
nextEventTime = this.nextVCounterEventTime() | 0;
|
||||
}
|
||||
return nextEventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.nextVBlankEventTime = function () {
|
||||
var nextEventTime = this.currentScanLine | 0;
|
||||
if ((nextEventTime | 0) < 160) {
|
||||
//Haven't reached vblank yet, so vblank offset - current:
|
||||
nextEventTime = (160 - (nextEventTime | 0)) | 0;
|
||||
}
|
||||
else {
|
||||
//We're in vblank, so it's end clock - current + next frame vblank offset:
|
||||
nextEventTime = (388 - (nextEventTime | 0)) | 0;
|
||||
}
|
||||
//Convert line count to clocks:
|
||||
nextEventTime = this.convertScanlineToClocks(nextEventTime | 0) | 0;
|
||||
//Subtract scanline offset from clocks:
|
||||
nextEventTime = ((nextEventTime | 0) - (this.LCDTicks | 0)) | 0;
|
||||
return nextEventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.nextHBlankDMAEventTime = function () {
|
||||
var nextEventTime = this.nextHBlankEventTime() | 0;
|
||||
if ((this.currentScanLine | 0) > 159 || ((this.currentScanLine | 0) == 159 && (this.LCDTicks | 0) >= 1006)) {
|
||||
//No HBlank DMA in VBlank:
|
||||
var linesToSkip = (227 - (this.currentScanLine | 0)) | 0;
|
||||
linesToSkip = this.convertScanlineToClocks(linesToSkip | 0) | 0;
|
||||
nextEventTime = ((nextEventTime | 0) + (linesToSkip | 0)) | 0;
|
||||
}
|
||||
return nextEventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.nextVCounterEventTime = function () {
|
||||
var nextEventTime = 0x7FFFFFFF;
|
||||
if ((this.VCounter | 0) <= 227) {
|
||||
//Only match lines within screen or vblank:
|
||||
nextEventTime = ((this.VCounter | 0) - (this.currentScanLine | 0)) | 0;
|
||||
if ((nextEventTime | 0) <= 0) {
|
||||
nextEventTime = ((nextEventTime | 0) + 228) | 0;
|
||||
}
|
||||
nextEventTime = this.convertScanlineToClocks(nextEventTime | 0) | 0;
|
||||
nextEventTime = ((nextEventTime | 0) - (this.LCDTicks | 0)) | 0;
|
||||
}
|
||||
return nextEventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.nextDisplaySyncEventTime = function (delay) {
|
||||
delay = delay | 0;
|
||||
var nextEventTime = 0x7FFFFFFF;
|
||||
if ((this.currentScanLine | 0) >= 161 || (delay | 0) != 0) {
|
||||
//Skip to line 2 metrics:
|
||||
nextEventTime = (230 - (this.currentScanLine | 0)) | 0;
|
||||
nextEventTime = this.convertScanlineToClocks(nextEventTime | 0) | 0;
|
||||
nextEventTime = ((nextEventTime | 0) - (this.LCDTicks | 0)) | 0;
|
||||
}
|
||||
else if ((this.currentScanLine | 0) == 0) {
|
||||
//Doesn't start until line 2:
|
||||
nextEventTime = (2464 - (this.LCDTicks | 0)) | 0;
|
||||
}
|
||||
else {
|
||||
//Line 2 through line 161:
|
||||
nextEventTime = (1232 - (this.LCDTicks | 0)) | 0;
|
||||
}
|
||||
return nextEventTime | 0;
|
||||
}
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceGraphics.prototype.convertScanlineToClocks = function (lines) {
|
||||
lines = lines | 0;
|
||||
lines = Math.imul(lines | 0, 1232) | 0;
|
||||
return lines | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceGraphics.prototype.convertScanlineToClocks = function (lines) {
|
||||
lines = lines | 0;
|
||||
lines = ((lines | 0) * 1232) | 0;
|
||||
return lines | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.updateVBlankStart = function () {
|
||||
this.statusFlags = this.statusFlags | 0x1; //Mark VBlank.
|
||||
if ((this.IRQFlags & 0x8) != 0) { //Check for VBlank IRQ.
|
||||
this.irq.requestIRQ(0x1);
|
||||
}
|
||||
this.gfxRenderer.ensureFraming();
|
||||
this.dma.gfxVBlankRequest();
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.isRenderingCheckPreprocess = function () {
|
||||
var isInVisibleLines = ((this.gfxRenderer.IOData8[0] & 0x80) == 0 && (this.statusFlags & 0x1) == 0);
|
||||
var isRendering = (isInVisibleLines && (this.statusFlags & 0x2) == 0) ? 2 : 1;
|
||||
var isOAMRendering = (isInVisibleLines && ((this.statusFlags & 0x2) == 0 || (this.gfxRenderer.IOData8[0] & 0x20) == 0)) ? 2 : 1;
|
||||
this.wait.updateRenderStatus(isRendering | 0, isOAMRendering | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.writeDISPSTAT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
//VBlank flag read only.
|
||||
//HBlank flag read only.
|
||||
//V-Counter flag read only.
|
||||
//Only LCD IRQ generation enablers can be set here:
|
||||
this.IRQFlags = data & 0x38;
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.writeDISPSTAT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
data = data & 0xFF;
|
||||
//V-Counter match value:
|
||||
if ((data | 0) != (this.VCounter | 0)) {
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.VCounter = data | 0;
|
||||
this.checkVCounter();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.writeDISPSTAT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
//VBlank flag read only.
|
||||
//HBlank flag read only.
|
||||
//V-Counter flag read only.
|
||||
//Only LCD IRQ generation enablers can be set here:
|
||||
this.IRQFlags = data & 0x38;
|
||||
data = (data >> 8) & 0xFF;
|
||||
//V-Counter match value:
|
||||
if ((data | 0) != (this.VCounter | 0)) {
|
||||
this.VCounter = data | 0;
|
||||
this.checkVCounter();
|
||||
}
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.readDISPSTAT8_0 = function () {
|
||||
this.IOCore.updateGraphicsClocking();
|
||||
return (this.statusFlags | this.IRQFlags);
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.readDISPSTAT8_1 = function () {
|
||||
return this.VCounter | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.readDISPSTAT8_2 = function () {
|
||||
this.IOCore.updateGraphicsClocking();
|
||||
return this.currentScanLine | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.readDISPSTAT16_0 = function () {
|
||||
this.IOCore.updateGraphicsClocking();
|
||||
return ((this.VCounter << 8) | this.statusFlags | this.IRQFlags);
|
||||
}
|
||||
GameBoyAdvanceGraphics.prototype.readDISPSTAT32 = function () {
|
||||
this.IOCore.updateGraphicsClocking();
|
||||
return ((this.currentScanLine << 16) | (this.VCounter << 8) | this.statusFlags | this.IRQFlags);
|
||||
}
|
180
public/gfiles/gba/IodineGBA/core/IRQ.js
Normal file
180
public/gfiles/gba/IodineGBA/core/IRQ.js
Normal file
|
@ -0,0 +1,180 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceIRQ(IOCore) {
|
||||
//Build references:
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.initialize = function () {
|
||||
this.interruptsEnabled = 0;
|
||||
this.interruptsRequested = 0;
|
||||
this.IME = 0;
|
||||
this.gfxState = this.IOCore.gfxState;
|
||||
this.timer = this.IOCore.timer;
|
||||
this.dmaChannel0 = this.IOCore.dmaChannel0;
|
||||
this.dmaChannel1 = this.IOCore.dmaChannel1;
|
||||
this.dmaChannel2 = this.IOCore.dmaChannel2;
|
||||
this.dmaChannel3 = this.IOCore.dmaChannel3;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.IRQMatch = function () {
|
||||
//Used to exit HALT:
|
||||
return (this.interruptsEnabled & this.interruptsRequested);
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.checkForIRQFire = function () {
|
||||
//Tell the CPU core when the emulated hardware is triggering an IRQ:
|
||||
this.IOCore.cpu.triggerIRQ(this.interruptsEnabled & this.interruptsRequested & this.IME);
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.requestIRQ = function (irqLineToSet) {
|
||||
irqLineToSet = irqLineToSet | 0;
|
||||
this.interruptsRequested = this.interruptsRequested | irqLineToSet;
|
||||
this.checkForIRQFire();
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.writeIME = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.IME = (data << 31) >> 31;
|
||||
this.checkForIRQFire();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.writeIE8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
var oldValue = this.interruptsEnabled & 0x3F00;
|
||||
data = data & 0xFF;
|
||||
data = data | oldValue;
|
||||
this.interruptsEnabled = data | 0;
|
||||
this.checkForIRQFire();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.writeIE8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
var oldValue = this.interruptsEnabled & 0xFF;
|
||||
data = (data & 0x3F) << 8;
|
||||
data = data | oldValue;
|
||||
this.interruptsEnabled = data | 0;
|
||||
this.checkForIRQFire();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.writeIE16 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.interruptsEnabled = data & 0x3FFF;
|
||||
this.checkForIRQFire();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.writeIF8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
data = ~(data & 0xFF);
|
||||
this.interruptsRequested = this.interruptsRequested & data;
|
||||
this.checkForIRQFire();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.writeIF8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
data = ~((data & 0xFF) << 8);
|
||||
this.interruptsRequested = this.interruptsRequested & data;
|
||||
this.checkForIRQFire();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.writeIF16 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
data = ~data;
|
||||
this.interruptsRequested = this.interruptsRequested & data;
|
||||
this.checkForIRQFire();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.writeIRQ32 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.interruptsEnabled = data & 0x3FFF;
|
||||
data = ~(data >> 16);
|
||||
this.interruptsRequested = this.interruptsRequested & data;
|
||||
this.checkForIRQFire();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.readIME = function () {
|
||||
var data = this.IME & 0x1;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.readIE8_0 = function () {
|
||||
var data = this.interruptsEnabled & 0xFF;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.readIE8_1 = function () {
|
||||
var data = this.interruptsEnabled >> 8;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.readIE16 = function () {
|
||||
var data = this.interruptsEnabled | 0;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.readIF8_0 = function () {
|
||||
this.IOCore.updateCoreSpillRetain();
|
||||
var data = this.interruptsRequested & 0xFF;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.readIF8_1 = function () {
|
||||
this.IOCore.updateCoreSpillRetain();
|
||||
var data = this.interruptsRequested >> 8;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.readIF16 = function () {
|
||||
this.IOCore.updateCoreSpillRetain();
|
||||
var data = this.interruptsRequested | 0;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.readIRQ32 = function () {
|
||||
this.IOCore.updateCoreSpillRetain();
|
||||
var data = (this.interruptsRequested << 16) | this.interruptsEnabled;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.nextEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
if ((this.interruptsEnabled & 0x1) != 0) {
|
||||
clocks = this.gfxState.nextVBlankIRQEventTime() | 0;
|
||||
}
|
||||
if ((this.interruptsEnabled & 0x2) != 0) {
|
||||
clocks = Math.min(clocks | 0, this.gfxState.nextHBlankIRQEventTime() | 0) | 0;
|
||||
}
|
||||
if ((this.interruptsEnabled & 0x4) != 0) {
|
||||
clocks = Math.min(clocks | 0, this.gfxState.nextVCounterIRQEventTime() | 0) | 0;
|
||||
}
|
||||
if ((this.interruptsEnabled & 0x8) != 0) {
|
||||
clocks = Math.min(clocks | 0, this.timer.nextTimer0IRQEventTime() | 0) | 0;
|
||||
}
|
||||
if ((this.interruptsEnabled & 0x10) != 0) {
|
||||
clocks = Math.min(clocks | 0, this.timer.nextTimer1IRQEventTime() | 0) | 0;
|
||||
}
|
||||
if ((this.interruptsEnabled & 0x20) != 0) {
|
||||
clocks = Math.min(clocks | 0, this.timer.nextTimer2IRQEventTime() | 0) | 0;
|
||||
}
|
||||
if ((this.interruptsEnabled & 0x40) != 0) {
|
||||
clocks = Math.min(clocks | 0, this.timer.nextTimer3IRQEventTime() | 0) | 0;
|
||||
}
|
||||
/*if ((this.interruptsEnabled & 0x80) != 0) {
|
||||
clocks = Math.min(clocks | 0, this.IOCore.serial.nextIRQEventTime() | 0) | 0;
|
||||
}
|
||||
if ((this.interruptsEnabled & 0x2000) != 0) {
|
||||
clocks = Math.min(clocks | 0, this.IOCore.cartridge.nextIRQEventTime() | 0) | 0;
|
||||
}*/
|
||||
return clocks | 0;
|
||||
}
|
||||
GameBoyAdvanceIRQ.prototype.nextIRQEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
//Checks IME:
|
||||
if ((this.IME | 0) != 0) {
|
||||
clocks = this.nextEventTime() | 0;
|
||||
}
|
||||
return clocks | 0;
|
||||
}
|
83
public/gfiles/gba/IodineGBA/core/JoyPad.js
Normal file
83
public/gfiles/gba/IodineGBA/core/JoyPad.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceJoyPad(IOCore) {
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.initialize = function () {
|
||||
this.keyInput = 0x3FF;
|
||||
this.keyInterrupt = 0;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.keyPress = function (keyPressed) {
|
||||
keyPressed = keyPressed | 0;
|
||||
keyPressed = 1 << (keyPressed | 0);
|
||||
this.keyInput = this.keyInput & (~keyPressed);
|
||||
this.checkForMatch();
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.keyRelease = function (keyReleased) {
|
||||
keyReleased = keyReleased | 0;
|
||||
keyReleased = 1 << (keyReleased | 0);
|
||||
this.keyInput = this.keyInput | keyReleased;
|
||||
this.checkForMatch();
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.checkForMatch = function () {
|
||||
if ((this.keyInterrupt & 0x8000) != 0) {
|
||||
if (((~this.keyInput) & this.keyInterrupt & 0x3FF) == (this.keyInterrupt & 0x3FF)) {
|
||||
this.IOCore.deflagStop();
|
||||
this.checkForIRQ();
|
||||
}
|
||||
}
|
||||
else if (((~this.keyInput) & this.keyInterrupt & 0x3FF) != 0) {
|
||||
this.IOCore.deflagStop();
|
||||
this.checkForIRQ();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.checkForIRQ = function () {
|
||||
if ((this.keyInterrupt & 0x4000) != 0) {
|
||||
this.IOCore.irq.requestIRQ(0x1000);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.readKeyStatus8_0 = function () {
|
||||
return this.keyInput & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.readKeyStatus8_1 = function () {
|
||||
return (this.keyInput >> 8) | 0;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.readKeyStatus16 = function () {
|
||||
return this.keyInput | 0;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.writeKeyControl8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.keyInterrupt = this.keyInterrupt & 0xC300;
|
||||
data = data & 0xFF;
|
||||
this.keyInterrupt = this.keyInterrupt | data;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.writeKeyControl8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.keyInterrupt = this.keyInterrupt & 0xFF;
|
||||
data = data & 0xC3;
|
||||
this.keyInterrupt = this.keyInterrupt | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.writeKeyControl16 = function (data) {
|
||||
data = data | 0;
|
||||
this.keyInterrupt = data & 0xC3FF;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.readKeyControl8_0 = function () {
|
||||
return this.keyInterrupt & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.readKeyControl8_1 = function () {
|
||||
return (this.keyInterrupt >> 8) | 0;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.readKeyControl16 = function () {
|
||||
return this.keyInterrupt | 0;
|
||||
}
|
||||
GameBoyAdvanceJoyPad.prototype.readKeyStatusControl32 = function () {
|
||||
return this.keyInput | (this.keyInterrupt << 16);
|
||||
}
|
5223
public/gfiles/gba/IodineGBA/core/Memory.js
Normal file
5223
public/gfiles/gba/IodineGBA/core/Memory.js
Normal file
File diff suppressed because it is too large
Load diff
428
public/gfiles/gba/IodineGBA/core/RunLoop.js
Normal file
428
public/gfiles/gba/IodineGBA/core/RunLoop.js
Normal file
|
@ -0,0 +1,428 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceIO(SKIPBoot, coreExposed, BIOS, ROM) {
|
||||
//State Machine Tracking:
|
||||
this.systemStatus = 0;
|
||||
this.cyclesToIterate = 0;
|
||||
this.cyclesOveriteratedPreviously = 0;
|
||||
this.accumulatedClocks = 0;
|
||||
this.graphicsClocks = 0;
|
||||
this.timerClocks = 0;
|
||||
this.serialClocks = 0;
|
||||
this.nextEventClocks = 0;
|
||||
//this.BIOSFound = false;
|
||||
//Do we skip the BIOS Boot Intro?
|
||||
this.SKIPBoot = !!SKIPBoot;
|
||||
//References passed to us:
|
||||
this.coreExposed = coreExposed;
|
||||
this.BIOS = BIOS;
|
||||
this.ROM = ROM;
|
||||
//Build the core object layout:
|
||||
this.memory = new GameBoyAdvanceMemory(this);
|
||||
this.dma = new GameBoyAdvanceDMA(this);
|
||||
this.dmaChannel0 = new GameBoyAdvanceDMA0(this);
|
||||
this.dmaChannel1 = new GameBoyAdvanceDMA1(this);
|
||||
this.dmaChannel2 = new GameBoyAdvanceDMA2(this);
|
||||
this.dmaChannel3 = new GameBoyAdvanceDMA3(this);
|
||||
this.gfxState = new GameBoyAdvanceGraphics(this);
|
||||
this.gfxRenderer = new GameBoyAdvanceRendererProxy(this);
|
||||
this.sound = new GameBoyAdvanceSound(this);
|
||||
this.timer = new GameBoyAdvanceTimer(this);
|
||||
this.irq = new GameBoyAdvanceIRQ(this);
|
||||
this.serial = new GameBoyAdvanceSerial(this);
|
||||
this.joypad = new GameBoyAdvanceJoyPad(this);
|
||||
this.cartridge = new GameBoyAdvanceCartridge(this);
|
||||
this.saves = new GameBoyAdvanceSaves(this);
|
||||
this.wait = new GameBoyAdvanceWait(this);
|
||||
this.cpu = new GameBoyAdvanceCPU(this);
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.initialize = function () {
|
||||
var allowInit = 1;
|
||||
//Now initialize each component:
|
||||
if ((this.memory.initialize() | 0) == 1) {
|
||||
//BIOS loaded in OK, so initialize the rest:
|
||||
this.dma.initialize();
|
||||
this.dmaChannel0.initialize();
|
||||
this.dmaChannel1.initialize();
|
||||
this.dmaChannel2.initialize();
|
||||
this.dmaChannel3.initialize();
|
||||
this.gfxState.initialize();
|
||||
this.gfxRenderer.initialize();
|
||||
this.sound.initialize();
|
||||
this.timer.initialize();
|
||||
this.irq.initialize();
|
||||
this.serial.initialize();
|
||||
this.joypad.initialize();
|
||||
this.cartridge.initialize();
|
||||
this.saves.initialize();
|
||||
this.wait.initialize();
|
||||
this.cpu.initialize();
|
||||
}
|
||||
else {
|
||||
allowInit = 0;
|
||||
}
|
||||
return allowInit | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.assignInstructionCoreReferences = function (ARM, THUMB) {
|
||||
//Passed here once the CPU component is initialized:
|
||||
this.ARM = ARM;
|
||||
this.THUMB = THUMB;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.enter = function (CPUCyclesTotal) {
|
||||
//Find out how many clocks to iterate through this run:
|
||||
this.cyclesToIterate = ((CPUCyclesTotal | 0) + (this.cyclesOveriteratedPreviously | 0)) | 0;
|
||||
//An extra check to make sure we don't do stuff if we did too much last run:
|
||||
if ((this.cyclesToIterate | 0) > 0) {
|
||||
//Update our core event prediction:
|
||||
this.updateCoreEventTime();
|
||||
//If clocks remaining, run iterator:
|
||||
this.run();
|
||||
//Spill our core event clocking:
|
||||
this.updateCoreClocking();
|
||||
//Ensure audio buffers at least once per iteration:
|
||||
this.sound.audioJIT();
|
||||
}
|
||||
//If we clocked just a little too much, subtract the extra from the next run:
|
||||
this.cyclesOveriteratedPreviously = this.cyclesToIterate | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.run = function () {
|
||||
//Clock through the state machine:
|
||||
while (true) {
|
||||
//Dispatch to optimized run loops:
|
||||
switch (this.systemStatus & 0x84) {
|
||||
case 0:
|
||||
//ARM instruction set:
|
||||
this.runARM();
|
||||
break;
|
||||
case 0x4:
|
||||
//THUMB instruction set:
|
||||
this.runTHUMB();
|
||||
break;
|
||||
default:
|
||||
//End of stepping:
|
||||
this.deflagIterationEnd();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.runARM = function () {
|
||||
//Clock through the state machine:
|
||||
while (true) {
|
||||
//Handle the current system state selected:
|
||||
switch (this.systemStatus | 0) {
|
||||
case 0: //CPU Handle State (Normal ARM)
|
||||
this.ARM.executeIteration();
|
||||
break;
|
||||
case 1:
|
||||
case 2: //CPU Handle State (Bubble ARM)
|
||||
this.ARM.executeBubble();
|
||||
this.tickBubble();
|
||||
break;
|
||||
default: //Handle lesser called / End of stepping
|
||||
//Dispatch on IRQ/DMA/HALT/STOP/END bit flags
|
||||
switch (this.systemStatus >> 2) {
|
||||
case 0x2:
|
||||
//IRQ Handle State:
|
||||
this.handleIRQARM();
|
||||
break;
|
||||
case 0x4:
|
||||
case 0x6:
|
||||
//DMA Handle State
|
||||
case 0xC:
|
||||
case 0xE:
|
||||
//DMA Inside Halt State
|
||||
this.handleDMA();
|
||||
break;
|
||||
case 0x8:
|
||||
case 0xA:
|
||||
//Handle Halt State
|
||||
this.handleHalt();
|
||||
break;
|
||||
default: //Handle Stop State
|
||||
//THUMB flagged stuff falls to here intentionally:
|
||||
//End of Stepping and/or CPU run loop switch:
|
||||
if ((this.systemStatus & 0x84) != 0) {
|
||||
return;
|
||||
}
|
||||
this.handleStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.runTHUMB = function () {
|
||||
//Clock through the state machine:
|
||||
while (true) {
|
||||
//Handle the current system state selected:
|
||||
switch (this.systemStatus | 0) {
|
||||
case 4: //CPU Handle State (Normal THUMB)
|
||||
this.THUMB.executeIteration();
|
||||
break;
|
||||
case 5:
|
||||
case 6: //CPU Handle State (Bubble THUMB)
|
||||
this.THUMB.executeBubble();
|
||||
this.tickBubble();
|
||||
break;
|
||||
default: //Handle lesser called / End of stepping
|
||||
//Dispatch on IRQ/DMA/HALT/STOP/END bit flags
|
||||
switch (this.systemStatus >> 2) {
|
||||
case 0x3:
|
||||
//IRQ Handle State:
|
||||
this.handleIRQThumb();
|
||||
break;
|
||||
case 0x5:
|
||||
case 0x7:
|
||||
//DMA Handle State
|
||||
case 0xD:
|
||||
case 0xF:
|
||||
//DMA Inside Halt State
|
||||
this.handleDMA();
|
||||
break;
|
||||
case 0x9:
|
||||
case 0x11:
|
||||
//Handle Halt State
|
||||
this.handleHalt();
|
||||
break;
|
||||
default: //Handle Stop State
|
||||
//ARM flagged stuff falls to here intentionally:
|
||||
//End of Stepping and/or CPU run loop switch:
|
||||
if ((this.systemStatus & 0x84) != 0x4) {
|
||||
return;
|
||||
}
|
||||
this.handleStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateCore = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
//This is used during normal/dma modes of operation:
|
||||
this.accumulatedClocks = ((this.accumulatedClocks | 0) + (clocks | 0)) | 0;
|
||||
if ((this.accumulatedClocks | 0) >= (this.nextEventClocks | 0)) {
|
||||
this.updateCoreSpill();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateCoreForce = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
//This is used during halt mode of operation:
|
||||
this.accumulatedClocks = ((this.accumulatedClocks | 0) + (clocks | 0)) | 0;
|
||||
this.updateCoreSpill();
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateCoreNegative = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
//This is used during normal/dma modes of operation:
|
||||
this.accumulatedClocks = ((this.accumulatedClocks | 0) - (clocks | 0)) | 0;
|
||||
if ((this.accumulatedClocks | 0) >= (this.nextEventClocks | 0)) {
|
||||
this.updateCoreSpill();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateCoreSingle = function () {
|
||||
//This is used during normal/dma modes of operation:
|
||||
this.accumulatedClocks = ((this.accumulatedClocks | 0) + 1) | 0;
|
||||
if ((this.accumulatedClocks | 0) >= (this.nextEventClocks | 0)) {
|
||||
this.updateCoreSpill();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateCoreSpill = function () {
|
||||
//Invalidate & recompute new event times:
|
||||
this.updateCoreClocking();
|
||||
this.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateCoreSpillRetain = function () {
|
||||
//Keep the last prediction, just decrement it out, as it's still valid:
|
||||
this.nextEventClocks = ((this.nextEventClocks | 0) - (this.accumulatedClocks | 0)) | 0;
|
||||
this.updateCoreClocking();
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateCoreClocking = function () {
|
||||
var clocks = this.accumulatedClocks | 0;
|
||||
//Decrement the clocks per iteration counter:
|
||||
this.cyclesToIterate = ((this.cyclesToIterate | 0) - (clocks | 0)) | 0;
|
||||
//Clock all components:
|
||||
this.gfxState.addClocks(((clocks | 0) - (this.graphicsClocks | 0)) | 0);
|
||||
this.timer.addClocks(((clocks | 0) - (this.timerClocks | 0)) | 0);
|
||||
this.serial.addClocks(((clocks | 0) - (this.serialClocks | 0)) | 0);
|
||||
this.accumulatedClocks = 0;
|
||||
this.graphicsClocks = 0;
|
||||
this.timerClocks = 0;
|
||||
this.serialClocks = 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateGraphicsClocking = function () {
|
||||
//Clock gfx component:
|
||||
this.gfxState.addClocks(((this.accumulatedClocks | 0) - (this.graphicsClocks | 0)) | 0);
|
||||
this.graphicsClocks = this.accumulatedClocks | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateTimerClocking = function () {
|
||||
//Clock timer component:
|
||||
this.timer.addClocks(((this.accumulatedClocks | 0) - (this.timerClocks | 0)) | 0);
|
||||
this.timerClocks = this.accumulatedClocks | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateSerialClocking = function () {
|
||||
//Clock serial component:
|
||||
this.serial.addClocks(((this.accumulatedClocks | 0) - (this.serialClocks | 0)) | 0);
|
||||
this.serialClocks = this.accumulatedClocks | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.updateCoreEventTime = function () {
|
||||
//Predict how many clocks until the next DMA or IRQ event:
|
||||
this.nextEventClocks = this.cyclesUntilNextEvent() | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.getRemainingCycles = function () {
|
||||
//Return the number of cycles left until iteration end:
|
||||
if ((this.cyclesToIterate | 0) < 1) {
|
||||
//Change our stepper to our end sequence:
|
||||
this.flagIterationEnd();
|
||||
return 0;
|
||||
}
|
||||
return this.cyclesToIterate | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.handleIRQARM = function () {
|
||||
if ((this.systemStatus | 0) > 0x8) {
|
||||
//CPU Handle State (Bubble ARM)
|
||||
this.ARM.executeBubble();
|
||||
this.tickBubble();
|
||||
}
|
||||
else {
|
||||
//CPU Handle State (IRQ)
|
||||
this.cpu.IRQinARM();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.handleIRQThumb = function () {
|
||||
if ((this.systemStatus | 0) > 0xC) {
|
||||
//CPU Handle State (Bubble THUMB)
|
||||
this.THUMB.executeBubble();
|
||||
this.tickBubble();
|
||||
}
|
||||
else {
|
||||
//CPU Handle State (IRQ)
|
||||
this.cpu.IRQinTHUMB();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.handleDMA = function () {
|
||||
/*
|
||||
Loop our state status in here as
|
||||
an optimized iteration, as DMA stepping instances
|
||||
happen in quick succession of each other, and
|
||||
aren't often done for one memory word only.
|
||||
*/
|
||||
do {
|
||||
//Perform a DMA read and write:
|
||||
this.dma.perform();
|
||||
} while ((this.systemStatus & 0x90) == 0x10);
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.handleHalt = function () {
|
||||
if ((this.irq.IRQMatch() | 0) == 0) {
|
||||
//Clock up to next IRQ match or DMA:
|
||||
this.updateCoreForce(this.cyclesUntilNextHALTEvent() | 0);
|
||||
}
|
||||
else {
|
||||
//Exit HALT promptly:
|
||||
this.deflagHalt();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.handleStop = function () {
|
||||
//Update sound system to add silence to buffer:
|
||||
this.sound.addClocks(this.getRemainingCycles() | 0);
|
||||
this.cyclesToIterate = 0;
|
||||
//Exits when user presses joypad or from an external irq outside of GBA internal.
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.cyclesUntilNextHALTEvent = function () {
|
||||
//Find the clocks to the next HALT leave or DMA event:
|
||||
var haltClocks = this.irq.nextEventTime() | 0;
|
||||
var dmaClocks = this.dma.nextEventTime() | 0;
|
||||
return this.solveClosestTime(haltClocks | 0, dmaClocks | 0) | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.cyclesUntilNextEvent = function () {
|
||||
//Find the clocks to the next IRQ or DMA event:
|
||||
var irqClocks = this.irq.nextIRQEventTime() | 0;
|
||||
var dmaClocks = this.dma.nextEventTime() | 0;
|
||||
return this.solveClosestTime(irqClocks | 0, dmaClocks | 0) | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.solveClosestTime = function (clocks1, clocks2) {
|
||||
clocks1 = clocks1 | 0;
|
||||
clocks2 = clocks2 | 0;
|
||||
//Find the clocks closest to the next event:
|
||||
var clocks = this.getRemainingCycles() | 0;
|
||||
clocks = Math.min(clocks | 0, clocks1 | 0, clocks2 | 0);
|
||||
return clocks | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.flagBubble = function () {
|
||||
//Flag a CPU pipeline bubble to step through:
|
||||
this.systemStatus = this.systemStatus | 0x2;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.tickBubble = function () {
|
||||
//Tick down a CPU pipeline bubble to step through:
|
||||
this.systemStatus = ((this.systemStatus | 0) - 1) | 0;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.flagTHUMB = function () {
|
||||
//Flag a CPU IRQ to step through:
|
||||
this.systemStatus = this.systemStatus | 0x4;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.deflagTHUMB = function () {
|
||||
//Deflag a CPU IRQ to step through:
|
||||
this.systemStatus = this.systemStatus & 0xFB;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.flagIRQ = function () {
|
||||
//Flag THUMB CPU mode to step through:
|
||||
this.systemStatus = this.systemStatus | 0x8;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.deflagIRQ = function () {
|
||||
//Deflag THUMB CPU mode to step through:
|
||||
this.systemStatus = this.systemStatus & 0xF7;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.flagDMA = function () {
|
||||
//Flag a DMA event to step through:
|
||||
this.systemStatus = this.systemStatus | 0x10;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.deflagDMA = function () {
|
||||
//Deflag a DMA event to step through:
|
||||
this.systemStatus = this.systemStatus & 0xEF;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.flagHalt = function () {
|
||||
//Flag a halt event to step through:
|
||||
this.systemStatus = this.systemStatus | 0x20;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.deflagHalt = function () {
|
||||
//Deflag a halt event to step through:
|
||||
this.systemStatus = this.systemStatus & 0xDF;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.flagStop = function () {
|
||||
//Flag a halt event to step through:
|
||||
this.systemStatus = this.systemStatus | 0x40;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.deflagStop = function () {
|
||||
//Deflag a halt event to step through:
|
||||
this.systemStatus = this.systemStatus & 0xBF;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.flagIterationEnd = function () {
|
||||
//Flag a run loop kill event to step through:
|
||||
this.systemStatus = this.systemStatus | 0x80;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.deflagIterationEnd = function () {
|
||||
//Deflag a run loop kill event to step through:
|
||||
this.systemStatus = this.systemStatus & 0x7F;
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.isStopped = function () {
|
||||
//Sound system uses this to emulate a unpowered audio output:
|
||||
return ((this.systemStatus & 0x40) != 0);
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.inDMA = function () {
|
||||
//Save system uses this to detect dma:
|
||||
return ((this.systemStatus & 0x10) != 0);
|
||||
}
|
||||
GameBoyAdvanceIO.prototype.getCurrentFetchValue = function () {
|
||||
//Last valid value output for bad reads:
|
||||
var fetch = 0;
|
||||
if ((this.systemStatus & 0x10) == 0) {
|
||||
fetch = this.cpu.getCurrentFetchValue() | 0;
|
||||
}
|
||||
else {
|
||||
fetch = this.dma.getCurrentFetchValue() | 0;
|
||||
}
|
||||
return fetch | 0;
|
||||
}
|
239
public/gfiles/gba/IodineGBA/core/Saves.js
Normal file
239
public/gfiles/gba/IodineGBA/core/Saves.js
Normal file
|
@ -0,0 +1,239 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceSaves(IOCore) {
|
||||
this.cartridge = IOCore.cartridge;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.initialize = function () {
|
||||
this.saveType = 0;
|
||||
this.GPIOChip = new GameBoyAdvanceGPIOChip();
|
||||
this.UNDETERMINED = new GameBoyAdvanceSaveDeterminer(this);
|
||||
this.SRAMChip = new GameBoyAdvanceSRAMChip();
|
||||
this.FLASHChip = new GameBoyAdvanceFLASHChip(this.cartridge.flash_is128, this.cartridge.flash_isAtmel);
|
||||
this.EEPROMChip = new GameBoyAdvanceEEPROMChip(this.cartridge.IOCore);
|
||||
this.currentChip = this.UNDETERMINED;
|
||||
this.referenceSave(this.saveType);
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.referenceSave = function (saveType) {
|
||||
saveType = saveType | 0;
|
||||
switch (saveType | 0) {
|
||||
case 0:
|
||||
this.currentChip = this.UNDETERMINED;
|
||||
break;
|
||||
case 1:
|
||||
this.currentChip = this.SRAMChip;
|
||||
break;
|
||||
case 2:
|
||||
this.currentChip = this.FLASHChip;
|
||||
break;
|
||||
case 3:
|
||||
this.currentChip = this.EEPROMChip;
|
||||
}
|
||||
this.currentChip.initialize();
|
||||
this.saveType = saveType | 0;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.importSave = function (saves, saveType) {
|
||||
saveType = saveType | 0;
|
||||
this.UNDETERMINED.load(saves);
|
||||
this.SRAMChip.load(saves);
|
||||
this.FLASHChip.load(saves);
|
||||
this.EEPROMChip.load(saves);
|
||||
this.referenceSave(saveType | 0);
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.importRTC = function (saves) {
|
||||
this.GPIOChip.loadRTC(saves);
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.importGPIOType = function (gpioType) {
|
||||
gpioType = gpioType | 0;
|
||||
this.GPIOChip.loadType(gpioType | 0);
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.exportSave = function () {
|
||||
return this.currentChip.saves;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.exportSaveType = function () {
|
||||
return this.saveType | 0;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.readGPIO8 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.GPIOChip.getType() | 0) > 0) {
|
||||
//GPIO:
|
||||
data = this.GPIOChip.read8(address | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//ROM:
|
||||
data = this.cartridge.readROMOnly8(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.readEEPROM8 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.saveType | 0) == 3) {
|
||||
//EEPROM:
|
||||
data = this.EEPROMChip.read8() | 0;
|
||||
}
|
||||
else {
|
||||
//UNKNOWN:
|
||||
data = this.UNDETERMINED.readEEPROM8(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.readGPIO16 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.GPIOChip.getType() | 0) > 0) {
|
||||
//GPIO:
|
||||
data = this.GPIOChip.read16(address | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//ROM:
|
||||
data = this.cartridge.readROMOnly16(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.readEEPROM16 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.saveType | 0) == 3) {
|
||||
//EEPROM:
|
||||
data = this.EEPROMChip.read16() | 0;
|
||||
}
|
||||
else {
|
||||
//UNKNOWN:
|
||||
data = this.UNDETERMINED.readEEPROM16(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.readGPIO32 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.GPIOChip.getType() | 0) > 0) {
|
||||
//GPIO:
|
||||
data = this.GPIOChip.read32(address | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//ROM:
|
||||
data = this.cartridge.readROMOnly32(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.readEEPROM32 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.saveType | 0) == 3) {
|
||||
//EEPROM:
|
||||
data = this.EEPROMChip.read32() | 0;
|
||||
}
|
||||
else {
|
||||
//UNKNOWN:
|
||||
data = this.UNDETERMINED.readEEPROM32(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.readSRAM = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
switch (this.saveType | 0) {
|
||||
case 0:
|
||||
//UNKNOWN:
|
||||
data = this.UNDETERMINED.readSRAM(address | 0) | 0;
|
||||
break;
|
||||
case 1:
|
||||
//SRAM:
|
||||
data = this.SRAMChip.read(address | 0) | 0;
|
||||
break;
|
||||
case 2:
|
||||
//FLASH:
|
||||
data = this.FLASHChip.read(address | 0) | 0;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.writeGPIO8 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((this.GPIOChip.getType() | 0) > 0) {
|
||||
//GPIO:
|
||||
this.GPIOChip.write8(address | 0, data | 0);
|
||||
}
|
||||
else {
|
||||
//Unknown:
|
||||
this.UNDETERMINED.writeGPIO8(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.writeGPIO16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((this.GPIOChip.getType() | 0) > 0) {
|
||||
//GPIO:
|
||||
this.GPIOChip.write16(address | 0, data | 0);
|
||||
}
|
||||
else {
|
||||
//Unknown:
|
||||
this.UNDETERMINED.writeGPIO16(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.writeEEPROM16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((this.saveType | 0) == 3) {
|
||||
//EEPROM:
|
||||
this.EEPROMChip.write16(data | 0);
|
||||
}
|
||||
else {
|
||||
//Unknown:
|
||||
this.UNDETERMINED.writeEEPROM16(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.writeGPIO32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((this.GPIOChip.getType() | 0) > 0) {
|
||||
//GPIO:
|
||||
this.GPIOChip.write32(address | 0, data | 0);
|
||||
}
|
||||
else {
|
||||
//Unknown:
|
||||
this.UNDETERMINED.writeGPIO32(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.writeSRAM = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
switch (this.saveType | 0) {
|
||||
case 0:
|
||||
//Unknown:
|
||||
this.UNDETERMINED.writeSRAM(address | 0, data | 0);
|
||||
break;
|
||||
case 1:
|
||||
//SRAM:
|
||||
this.SRAMChip.write(address | 0, data | 0);
|
||||
break;
|
||||
case 2:
|
||||
//FLASH:
|
||||
this.FLASHChip.write(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaves.prototype.writeSRAMIfDefined = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
switch (this.saveType | 0) {
|
||||
case 0:
|
||||
//UNKNOWN:
|
||||
this.SRAMChip.initialize();
|
||||
case 1:
|
||||
//SRAM:
|
||||
this.SRAMChip.write(address | 0, data | 0);
|
||||
break;
|
||||
case 2:
|
||||
//FLASH:
|
||||
this.FLASHChip.write(address | 0, data | 0);
|
||||
}
|
||||
}
|
437
public/gfiles/gba/IodineGBA/core/Serial.js
Normal file
437
public/gfiles/gba/IodineGBA/core/Serial.js
Normal file
|
@ -0,0 +1,437 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceSerial(IOCore) {
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.initialize = function () {
|
||||
this.SIODATA_A = 0xFFFF;
|
||||
this.SIODATA_B = 0xFFFF;
|
||||
this.SIODATA_C = 0xFFFF;
|
||||
this.SIODATA_D = 0xFFFF;
|
||||
this.SIOShiftClockExternal = 0;
|
||||
this.SIOShiftClockDivider = 0x40;
|
||||
this.SIOCNT0_DATA = 0x0C;
|
||||
this.SIOTransferStarted = false;
|
||||
this.SIOMULT_PLAYER_NUMBER = 0;
|
||||
this.SIOCOMMERROR = false;
|
||||
this.SIOBaudRate = 0;
|
||||
this.SIOCNT_UART_CTS = false;
|
||||
this.SIOCNT_UART_MISC = 0;
|
||||
this.SIOCNT_UART_FIFO = 0;
|
||||
this.SIOCNT_IRQ = 0;
|
||||
this.SIOCNT_MODE = 0;
|
||||
this.SIOCNT_UART_RECV_ENABLE = false;
|
||||
this.SIOCNT_UART_SEND_ENABLE = false;
|
||||
this.SIOCNT_UART_PARITY_ENABLE = false;
|
||||
this.SIOCNT_UART_FIFO_ENABLE = false;
|
||||
this.SIODATA8 = 0xFFFF;
|
||||
this.RCNTMode = 0;
|
||||
this.RCNTIRQ = false;
|
||||
this.RCNTDataBits = 0;
|
||||
this.RCNTDataBitFlow = 0;
|
||||
this.JOYBUS_IRQ = 0;
|
||||
this.JOYBUS_CNTL_FLAGS = 0;
|
||||
this.JOYBUS_RECV0 = 0xFF;
|
||||
this.JOYBUS_RECV1 = 0xFF;
|
||||
this.JOYBUS_RECV2 = 0xFF;
|
||||
this.JOYBUS_RECV3 = 0xFF;
|
||||
this.JOYBUS_SEND0 = 0xFF;
|
||||
this.JOYBUS_SEND1 = 0xFF;
|
||||
this.JOYBUS_SEND2 = 0xFF;
|
||||
this.JOYBUS_SEND3 = 0xFF;
|
||||
this.JOYBUS_STAT = 0;
|
||||
this.shiftClocks = 0;
|
||||
this.serialBitsShifted = 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.SIOMultiplayerBaudRate = [
|
||||
9600,
|
||||
38400,
|
||||
57600,
|
||||
115200
|
||||
];
|
||||
GameBoyAdvanceSerial.prototype.addClocks = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
if ((this.RCNTMode | 0) < 2) {
|
||||
switch (this.SIOCNT_MODE | 0) {
|
||||
case 0:
|
||||
case 1:
|
||||
if (this.SIOTransferStarted && (this.SIOShiftClockExternal | 0) == 0) {
|
||||
this.shiftClocks = ((this.shiftClocks | 0) + (clocks | 0)) | 0;
|
||||
while ((this.shiftClocks | 0) >= (this.SIOShiftClockDivider | 0)) {
|
||||
this.shiftClocks = ((this.shiftClocks | 0) - (this.SIOShiftClockDivider | 0)) | 0;
|
||||
this.clockSerial();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (this.SIOTransferStarted && (this.SIOMULT_PLAYER_NUMBER | 0) == 0) {
|
||||
this.shiftClocks = ((this.shiftClocks | 0) + (clocks | 0)) | 0;
|
||||
while ((this.shiftClocks | 0) >= (this.SIOShiftClockDivider | 0)) {
|
||||
this.shiftClocks = ((this.shiftClocks | 0) - (this.SIOShiftClockDivider | 0)) | 0;
|
||||
this.clockMultiplayer();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (this.SIOCNT_UART_SEND_ENABLE && !this.SIOCNT_UART_CTS) {
|
||||
this.shiftClocks = ((this.shiftClocks | 0) + (clocks | 0)) | 0;
|
||||
while ((this.shiftClocks | 0) >= (this.SIOShiftClockDivider | 0)) {
|
||||
this.shiftClocks = ((this.shiftClocks | 0) - (this.SIOShiftClockDivider | 0)) | 0;
|
||||
this.clockUART();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.clockSerial = function () {
|
||||
//Emulate as if no slaves connected:
|
||||
this.serialBitsShifted = ((this.serialBitsShifted | 0) + 1) | 0;
|
||||
if ((this.SIOCNT_MODE | 0) == 0) {
|
||||
//8-bit
|
||||
this.SIODATA8 = ((this.SIODATA8 << 1) | 1) & 0xFFFF;
|
||||
if ((this.serialBitsShifted | 0) == 8) {
|
||||
this.SIOTransferStarted = false;
|
||||
this.serialBitsShifted = 0;
|
||||
if ((this.SIOCNT_IRQ | 0) != 0) {
|
||||
//this.IOCore.irq.requestIRQ(0x80);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//32-bit
|
||||
this.SIODATA_D = ((this.SIODATA_D << 1) & 0xFE) | (this.SIODATA_C >> 7);
|
||||
this.SIODATA_C = ((this.SIODATA_C << 1) & 0xFE) | (this.SIODATA_B >> 7);
|
||||
this.SIODATA_B = ((this.SIODATA_B << 1) & 0xFE) | (this.SIODATA_A >> 7);
|
||||
this.SIODATA_A = ((this.SIODATA_A << 1) & 0xFE) | 1;
|
||||
if ((this.serialBitsShifted | 0) == 32) {
|
||||
this.SIOTransferStarted = false;
|
||||
this.serialBitsShifted = 0;
|
||||
if ((this.SIOCNT_IRQ | 0) != 0) {
|
||||
//this.IOCore.irq.requestIRQ(0x80);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.clockMultiplayer = function () {
|
||||
//Emulate as if no slaves connected:
|
||||
this.SIODATA_A = this.SIODATA8 | 0;
|
||||
this.SIODATA_B = 0xFFFF;
|
||||
this.SIODATA_C = 0xFFFF;
|
||||
this.SIODATA_D = 0xFFFF;
|
||||
this.SIOTransferStarted = false;
|
||||
this.SIOCOMMERROR = true;
|
||||
if ((this.SIOCNT_IRQ | 0) != 0) {
|
||||
//this.IOCore.irq.requestIRQ(0x80);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.clockUART = function () {
|
||||
this.serialBitsShifted = ((this.serialBitsShifted | 0) + 1) | 0;
|
||||
if (this.SIOCNT_UART_FIFO_ENABLE) {
|
||||
if ((this.serialBitsShifted | 0) == 8) {
|
||||
this.serialBitsShifted = 0;
|
||||
this.SIOCNT_UART_FIFO = Math.max(((this.SIOCNT_UART_FIFO | 0) - 1) | 0, 0) | 0;
|
||||
if ((this.SIOCNT_UART_FIFO | 0) == 0 && (this.SIOCNT_IRQ | 0) != 0) {
|
||||
//this.IOCore.irq.requestIRQ(0x80);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((this.serialBitsShifted | 0) == 8) {
|
||||
this.serialBitsShifted = 0;
|
||||
if ((this.SIOCNT_IRQ | 0) != 0) {
|
||||
//this.IOCore.irq.requestIRQ(0x80);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA_A0 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA_A = (this.SIODATA_A & 0xFF00) | data;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA_A0 = function () {
|
||||
return this.SIODATA_A & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA_A1 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA_A = (this.SIODATA_A & 0xFF) | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA_A1 = function () {
|
||||
return this.SIODATA_A >> 8;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA_B0 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA_B = (this.SIODATA_B & 0xFF00) | data;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA_B0 = function () {
|
||||
return this.SIODATA_B & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA_B1 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA_B = (this.SIODATA_B & 0xFF) | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA_B1 = function () {
|
||||
return this.SIODATA_B >> 8;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA_C0 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA_C = (this.SIODATA_C & 0xFF00) | data;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA_C0 = function () {
|
||||
return this.SIODATA_C & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA_C1 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA_C = (this.SIODATA_C & 0xFF) | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA_C1 = function () {
|
||||
return this.SIODATA_C >> 8;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA_D0 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA_D = (this.SIODATA_D & 0xFF00) | data;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA_D0 = function () {
|
||||
return this.SIODATA_D & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA_D1 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA_D = (this.SIODATA_D & 0xFF) | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA_D1 = function () {
|
||||
return this.SIODATA_D >> 8;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIOCNT0 = function (data) {
|
||||
if ((this.RCNTMode | 0) < 0x2) {
|
||||
switch (this.SIOCNT_MODE | 0) {
|
||||
//8-Bit:
|
||||
case 0:
|
||||
//32-Bit:
|
||||
case 1:
|
||||
this.SIOShiftClockExternal = data & 0x1;
|
||||
this.SIOShiftClockDivider = ((data & 0x2) != 0) ? 0x8 : 0x40;
|
||||
this.SIOCNT0_DATA = data & 0xB;
|
||||
if ((data & 0x80) != 0) {
|
||||
if (!this.SIOTransferStarted) {
|
||||
this.SIOTransferStarted = true;
|
||||
this.serialBitsShifted = 0;
|
||||
this.shiftClocks = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.SIOTransferStarted = false;
|
||||
}
|
||||
break;
|
||||
//Multiplayer:
|
||||
case 2:
|
||||
this.SIOBaudRate = data & 0x3;
|
||||
this.SIOShiftClockDivider = this.SIOMultiplayerBaudRate[this.SIOBaudRate | 0] | 0;
|
||||
this.SIOMULT_PLAYER_NUMBER = (data >> 4) & 0x3;
|
||||
this.SIOCOMMERROR = ((data & 0x40) != 0);
|
||||
if ((data & 0x80) != 0) {
|
||||
if (!this.SIOTransferStarted) {
|
||||
this.SIOTransferStarted = true;
|
||||
if ((this.SIOMULT_PLAYER_NUMBER | 0) == 0) {
|
||||
this.SIODATA_A = 0xFFFF;
|
||||
this.SIODATA_B = 0xFFFF;
|
||||
this.SIODATA_C = 0xFFFF;
|
||||
this.SIODATA_D = 0xFFFF;
|
||||
}
|
||||
this.serialBitsShifted = 0;
|
||||
this.shiftClocks = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.SIOTransferStarted = false;
|
||||
}
|
||||
break;
|
||||
//UART:
|
||||
case 3:
|
||||
this.SIOBaudRate = data & 0x3;
|
||||
this.SIOShiftClockDivider = this.SIOMultiplayerBaudRate[this.SIOBaudRate | 0] | 0;
|
||||
this.SIOCNT_UART_MISC = (data & 0xCF) >> 2;
|
||||
this.SIOCNT_UART_CTS = ((data & 0x4) != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIOCNT0 = function () {
|
||||
if (this.RCNTMode < 0x2) {
|
||||
switch (this.SIOCNT_MODE) {
|
||||
//8-Bit:
|
||||
case 0:
|
||||
//32-Bit:
|
||||
case 1:
|
||||
return ((this.SIOTransferStarted) ? 0x80 : 0) | 0x74 | this.SIOCNT0_DATA;
|
||||
//Multiplayer:
|
||||
case 2:
|
||||
return ((this.SIOTransferStarted) ? 0x80 : 0) | ((this.SIOCOMMERROR) ? 0x40 : 0) | (this.SIOMULT_PLAYER_NUMBER << 4) | this.SIOBaudRate;
|
||||
//UART:
|
||||
case 3:
|
||||
return (this.SIOCNT_UART_MISC << 2) | ((this.SIOCNT_UART_FIFO == 4) ? 0x30 : 0x20) | this.SIOBaudRate;
|
||||
}
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIOCNT1 = function (data) {
|
||||
this.SIOCNT_IRQ = data & 0x40;
|
||||
this.SIOCNT_MODE = (data >> 4) & 0x3;
|
||||
this.SIOCNT_UART_RECV_ENABLE = ((data & 0x8) != 0);
|
||||
this.SIOCNT_UART_SEND_ENABLE = ((data & 0x4) != 0);
|
||||
this.SIOCNT_UART_PARITY_ENABLE = ((data & 0x2) != 0);
|
||||
this.SIOCNT_UART_FIFO_ENABLE = ((data & 0x1) != 0);
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIOCNT1 = function () {
|
||||
return (0x80 | this.SIOCNT_IRQ | (this.SIOCNT_MODE << 4) | ((this.SIOCNT_UART_RECV_ENABLE) ? 0x8 : 0) |
|
||||
((this.SIOCNT_UART_SEND_ENABLE) ? 0x4 : 0) | ((this.SIOCNT_UART_PARITY_ENABLE) ? 0x2 : 0) | ((this.SIOCNT_UART_FIFO_ENABLE) ? 0x2 : 0));
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA8 = (this.SIODATA8 & 0xFF00) | data;
|
||||
if ((this.RCNTMode | 0) < 0x2 && (this.SIOCNT_MODE | 0) == 3 && this.SIOCNT_UART_FIFO_ENABLE) {
|
||||
this.SIOCNT_UART_FIFO = Math.min(((this.SIOCNT_UART_FIFO | 0) + 1) | 0, 4) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA8_0 = function () {
|
||||
return this.SIODATA8 & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeSIODATA8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.SIODATA8 = (this.SIODATA8 & 0xFF) | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readSIODATA8_1 = function () {
|
||||
return this.SIODATA8 >> 8;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeRCNT0 = function (data) {
|
||||
if ((this.RCNTMode | 0) == 0x2) {
|
||||
//General Comm:
|
||||
var oldDataBits = this.RCNTDataBits | 0;
|
||||
this.RCNTDataBits = data & 0xF; //Device manually controls SI/SO/SC/SD here.
|
||||
this.RCNTDataBitFlow = data >> 4;
|
||||
if (this.RCNTIRQ && ((oldDataBits ^ this.RCNTDataBits) & oldDataBits & 0x4) != 0) {
|
||||
//SI fell low, trigger IRQ:
|
||||
//this.IOCore.irq.requestIRQ(0x80);
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readRCNT0 = function () {
|
||||
return (this.RCNTDataBitFlow << 4) | this.RCNTDataBits;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeRCNT1 = function (data) {
|
||||
this.RCNTMode = data >> 6;
|
||||
this.RCNTIRQ = ((data & 0x1) != 0);
|
||||
if ((this.RCNTMode | 0) != 0x2) {
|
||||
//Force SI/SO/SC/SD to low as we're never "hooked" up:
|
||||
this.RCNTDataBits = 0;
|
||||
this.RCNTDataBitFlow = 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readRCNT1 = function () {
|
||||
return (this.RCNTMode << 6) | ((this.RCNTIRQ) ? 0x3F : 0x3E);
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYCNT = function (data) {
|
||||
this.JOYBUS_IRQ = (data << 25) >> 31;
|
||||
this.JOYBUS_CNTL_FLAGS &= ~(data & 0x7);
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYCNT = function () {
|
||||
return (this.JOYBUS_CNTL_FLAGS | 0x40) | (0xB8 & this.JOYBUS_IRQ);
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYBUS_RECV0 = function (data) {
|
||||
this.JOYBUS_RECV0 = data | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYBUS_RECV0 = function () {
|
||||
this.JOYBUS_STAT = this.JOYBUS_STAT & 0xF7;
|
||||
return this.JOYBUS_RECV0 | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYBUS_RECV1 = function (data) {
|
||||
this.JOYBUS_RECV1 = data | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYBUS_RECV1 = function () {
|
||||
this.JOYBUS_STAT = this.JOYBUS_STAT & 0xF7;
|
||||
return this.JOYBUS_RECV1 | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYBUS_RECV2 = function (data) {
|
||||
this.JOYBUS_RECV2 = data | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYBUS_RECV2 = function () {
|
||||
this.JOYBUS_STAT = this.JOYBUS_STAT & 0xF7;
|
||||
return this.JOYBUS_RECV2 | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYBUS_RECV3 = function (data) {
|
||||
this.JOYBUS_RECV3 = data | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYBUS_RECV3 = function () {
|
||||
this.JOYBUS_STAT = this.JOYBUS_STAT & 0xF7;
|
||||
return this.JOYBUS_RECV3 | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYBUS_SEND0 = function (data) {
|
||||
this.JOYBUS_SEND0 = data | 0;
|
||||
this.JOYBUS_STAT = this.JOYBUS_STAT | 0x2;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYBUS_SEND0 = function () {
|
||||
return this.JOYBUS_SEND0 | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYBUS_SEND1 = function (data) {
|
||||
this.JOYBUS_SEND1 = data | 0;
|
||||
this.JOYBUS_STAT = this.JOYBUS_STAT | 0x2;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYBUS_SEND1 = function () {
|
||||
return this.JOYBUS_SEND1 | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYBUS_SEND2 = function (data) {
|
||||
this.JOYBUS_SEND2 = data | 0;
|
||||
this.JOYBUS_STAT = this.JOYBUS_STAT | 0x2;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYBUS_SEND2 = function () {
|
||||
return this.JOYBUS_SEND2 | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYBUS_SEND3 = function (data) {
|
||||
this.JOYBUS_SEND3 = data | 0;
|
||||
this.JOYBUS_STAT = this.JOYBUS_STAT | 0x2;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYBUS_SEND3 = function () {
|
||||
return this.JOYBUS_SEND3 | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.writeJOYBUS_STAT = function (data) {
|
||||
this.JOYBUS_STAT = data | 0;
|
||||
}
|
||||
GameBoyAdvanceSerial.prototype.readJOYBUS_STAT = function () {
|
||||
return 0xC5 | this.JOYBUS_STAT;
|
||||
}
|
||||
/*GameBoyAdvanceSerial.prototype.nextIRQEventTime = function (clocks) {
|
||||
if ((this.SIOCNT_IRQ | 0) != 0 && (this.RCNTMode | 0) < 2) {
|
||||
switch (this.SIOCNT_MODE | 0) {
|
||||
case 0:
|
||||
case 1:
|
||||
if (this.SIOTransferStarted && (this.SIOShiftClockExternal | 0) == 0) {
|
||||
return ((((this.SIOCNT_MODE == 1) ? 31 : 7) - this.serialBitsShifted) * this.SIOShiftClockDivider) + (this.SIOShiftClockDivider - this.shiftClocks);
|
||||
}
|
||||
else {
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
case 2:
|
||||
if (this.SIOTransferStarted && this.SIOMULT_PLAYER_NUMBER == 0) {
|
||||
return this.SIOShiftClockDivider - this.shiftClocks;
|
||||
}
|
||||
else {
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
case 3:
|
||||
if (this.SIOCNT_UART_SEND_ENABLE && !this.SIOCNT_UART_CTS) {
|
||||
return (Math.max(((this.SIOCNT_UART_FIFO_ENABLE) ? (this.SIOCNT_UART_FIFO * 8) : 8) - 1, 0) * this.SIOShiftClockDivider) + (this.SIOShiftClockDivider - this.shiftClocks);
|
||||
}
|
||||
else {
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0x7FFFFFFF;
|
||||
}
|
||||
}*/
|
1082
public/gfiles/gba/IodineGBA/core/Sound.js
Normal file
1082
public/gfiles/gba/IodineGBA/core/Sound.js
Normal file
File diff suppressed because it is too large
Load diff
846
public/gfiles/gba/IodineGBA/core/Timer.js
Normal file
846
public/gfiles/gba/IodineGBA/core/Timer.js
Normal file
|
@ -0,0 +1,846 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceTimer(IOCore) {
|
||||
//Build references:
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.prescalarLookup = [
|
||||
0,
|
||||
0x6,
|
||||
0x8,
|
||||
0xA
|
||||
];
|
||||
GameBoyAdvanceTimer.prototype.initialize = function () {
|
||||
this.timer0Counter = 0;
|
||||
this.timer0Reload = 0;
|
||||
this.timer0Control = 0;
|
||||
this.timer0Enabled = false;
|
||||
this.timer0IRQ = false;
|
||||
this.timer0Precounter = 0;
|
||||
this.timer0Prescalar = 1;
|
||||
this.timer0PrescalarShifted = 0;
|
||||
this.timer1Counter = 0;
|
||||
this.timer1Reload = 0;
|
||||
this.timer1Control = 0;
|
||||
this.timer1Enabled = false;
|
||||
this.timer1IRQ = false;
|
||||
this.timer1Precounter = 0;
|
||||
this.timer1Prescalar = 1;
|
||||
this.timer1PrescalarShifted = 0;
|
||||
this.timer1CountUp = false;
|
||||
this.timer2Counter = 0;
|
||||
this.timer2Reload = 0;
|
||||
this.timer2Control = 0;
|
||||
this.timer2Enabled = false;
|
||||
this.timer2IRQ = false;
|
||||
this.timer2Precounter = 0;
|
||||
this.timer2Prescalar = 1;
|
||||
this.timer2PrescalarShifted = 0;
|
||||
this.timer2CountUp = false;
|
||||
this.timer3Counter = 0;
|
||||
this.timer3Reload = 0;
|
||||
this.timer3Control = 0;
|
||||
this.timer3Enabled = false;
|
||||
this.timer3IRQ = false;
|
||||
this.timer3Precounter = 0;
|
||||
this.timer3Prescalar = 1;
|
||||
this.timer3PrescalarShifted = 0;
|
||||
this.timer3CountUp = false;
|
||||
this.timer1UseMainClocks = false;
|
||||
this.timer1UseChainedClocks = false;
|
||||
this.timer2UseMainClocks = false;
|
||||
this.timer2UseChainedClocks = false;
|
||||
this.timer3UseMainClocks = false;
|
||||
this.timer3UseChainedClocks = false;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.addClocks = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
//See if timer channels 0 and 1 are enabled:
|
||||
this.clockSoundTimers(clocks | 0);
|
||||
//See if timer channel 2 is enabled:
|
||||
this.clockTimer2(clocks | 0);
|
||||
//See if timer channel 3 is enabled:
|
||||
this.clockTimer3(clocks | 0);
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.clockSoundTimers = function (audioClocks) {
|
||||
audioClocks = audioClocks | 0;
|
||||
for (var predictedClocks = 0, overflowClocks = 0; (audioClocks | 0) > 0; audioClocks = ((audioClocks | 0) - (predictedClocks | 0)) | 0) {
|
||||
overflowClocks = this.nextAudioTimerOverflow() | 0;
|
||||
predictedClocks = Math.min(audioClocks | 0, overflowClocks | 0) | 0;
|
||||
//See if timer channel 0 is enabled:
|
||||
this.clockTimer0(predictedClocks | 0);
|
||||
//See if timer channel 1 is enabled:
|
||||
this.clockTimer1(predictedClocks | 0);
|
||||
//Clock audio system up to latest timer:
|
||||
this.IOCore.sound.addClocks(predictedClocks | 0);
|
||||
//Only jit if overflow was seen:
|
||||
if ((overflowClocks | 0) == (predictedClocks | 0)) {
|
||||
this.IOCore.sound.audioJIT();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.clockTimer0 = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
if (this.timer0Enabled) {
|
||||
this.timer0Precounter = ((this.timer0Precounter | 0) + (clocks | 0)) | 0;
|
||||
while ((this.timer0Precounter | 0) >= (this.timer0Prescalar | 0)) {
|
||||
var iterations = Math.min(this.timer0Precounter >> (this.timer0PrescalarShifted | 0), (0x10000 - (this.timer0Counter | 0)) | 0) | 0;
|
||||
this.timer0Precounter = ((this.timer0Precounter | 0) - ((iterations | 0) << (this.timer0PrescalarShifted | 0))) | 0;
|
||||
this.timer0Counter = ((this.timer0Counter | 0) + (iterations | 0)) | 0;
|
||||
if ((this.timer0Counter | 0) > 0xFFFF) {
|
||||
this.timer0Counter = this.timer0Reload | 0;
|
||||
this.timer0ExternalTriggerCheck();
|
||||
this.timer1ClockUpTickCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.clockTimer1 = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
if (this.timer1UseMainClocks) {
|
||||
this.timer1Precounter = ((this.timer1Precounter | 0) + (clocks | 0)) | 0;
|
||||
while ((this.timer1Precounter | 0) >= (this.timer1Prescalar | 0)) {
|
||||
var iterations = Math.min(this.timer1Precounter >> (this.timer1PrescalarShifted | 0), (0x10000 - (this.timer1Counter | 0)) | 0) | 0;
|
||||
this.timer1Precounter = ((this.timer1Precounter | 0) - ((iterations | 0) << (this.timer1PrescalarShifted | 0))) | 0;
|
||||
this.timer1Counter = ((this.timer1Counter | 0) + (iterations | 0)) | 0;
|
||||
if ((this.timer1Counter | 0) > 0xFFFF) {
|
||||
this.timer1Counter = this.timer1Reload | 0;
|
||||
this.timer1ExternalTriggerCheck();
|
||||
this.timer2ClockUpTickCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.clockTimer2 = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
if (this.timer2UseMainClocks) {
|
||||
this.timer2Precounter = ((this.timer2Precounter | 0) + (clocks | 0)) | 0;
|
||||
while ((this.timer2Precounter | 0) >= (this.timer2Prescalar | 0)) {
|
||||
var iterations = Math.min(this.timer2Precounter >> (this.timer2PrescalarShifted | 0), (0x10000 - (this.timer2Counter | 0)) | 0) | 0;
|
||||
this.timer2Precounter = ((this.timer2Precounter | 0) - ((iterations | 0) << (this.timer2PrescalarShifted | 0))) | 0;
|
||||
this.timer2Counter = ((this.timer2Counter | 0) + (iterations | 0)) | 0;
|
||||
if ((this.timer2Counter | 0) > 0xFFFF) {
|
||||
this.timer2Counter = this.timer2Reload | 0;
|
||||
this.timer2ExternalTriggerCheck();
|
||||
this.timer3ClockUpTickCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.clockTimer3 = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
if (this.timer3UseMainClocks) {
|
||||
this.timer3Precounter = ((this.timer3Precounter | 0) + (clocks | 0)) | 0;
|
||||
while ((this.timer3Precounter | 0) >= (this.timer3Prescalar | 0)) {
|
||||
var iterations = Math.min(this.timer3Precounter >> (this.timer3PrescalarShifted | 0), (0x10000 - (this.timer3Counter | 0)) | 0) | 0;
|
||||
this.timer3Precounter = ((this.timer3Precounter | 0) - ((iterations | 0) << (this.timer3PrescalarShifted | 0))) | 0;
|
||||
this.timer3Counter = ((this.timer3Counter | 0) + (iterations | 0)) | 0;
|
||||
if ((this.timer3Counter | 0) > 0xFFFF) {
|
||||
this.timer3Counter = this.timer3Reload | 0;
|
||||
this.timer3ExternalTriggerCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.timer1ClockUpTickCheck = function () {
|
||||
if (this.timer1UseChainedClocks) {
|
||||
this.timer1Counter = ((this.timer1Counter | 0) + 1) | 0;
|
||||
if ((this.timer1Counter | 0) > 0xFFFF) {
|
||||
this.timer1Counter = this.timer1Reload | 0;
|
||||
this.timer1ExternalTriggerCheck();
|
||||
this.timer2ClockUpTickCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.timer2ClockUpTickCheck = function () {
|
||||
if (this.timer2UseChainedClocks) {
|
||||
this.timer2Counter = ((this.timer2Counter | 0) + 1) | 0;
|
||||
if ((this.timer2Counter | 0) > 0xFFFF) {
|
||||
this.timer2Counter = this.timer2Reload | 0;
|
||||
this.timer2ExternalTriggerCheck();
|
||||
this.timer3ClockUpTickCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.timer3ClockUpTickCheck = function () {
|
||||
if (this.timer3UseChainedClocks) {
|
||||
this.timer3Counter = ((this.timer3Counter | 0) + 1) | 0;
|
||||
if ((this.timer3Counter | 0) > 0xFFFF) {
|
||||
this.timer3Counter = this.timer3Reload | 0;
|
||||
this.timer3ExternalTriggerCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.timer0ExternalTriggerCheck = function () {
|
||||
if (this.timer0IRQ) {
|
||||
this.IOCore.irq.requestIRQ(0x08);
|
||||
}
|
||||
this.IOCore.sound.AGBDirectSoundTimer0ClockTick();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.timer1ExternalTriggerCheck = function () {
|
||||
if (this.timer1IRQ) {
|
||||
this.IOCore.irq.requestIRQ(0x10);
|
||||
}
|
||||
this.IOCore.sound.AGBDirectSoundTimer1ClockTick();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.timer2ExternalTriggerCheck = function () {
|
||||
if (this.timer2IRQ) {
|
||||
this.IOCore.irq.requestIRQ(0x20);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.timer3ExternalTriggerCheck = function () {
|
||||
if (this.timer3IRQ) {
|
||||
this.IOCore.irq.requestIRQ(0x40);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM0CNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer0Reload = this.timer0Reload & 0xFF00;
|
||||
data = data & 0xFF;
|
||||
this.timer0Reload = this.timer0Reload | data;
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM0CNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer0Reload = this.timer0Reload & 0xFF;
|
||||
data = data & 0xFF;
|
||||
this.timer0Reload = this.timer0Reload | (data << 8);
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM0CNT8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer0Control = data & 0xFF;
|
||||
if ((data & 0x80) != 0) {
|
||||
if (!this.timer0Enabled) {
|
||||
this.timer0Counter = this.timer0Reload | 0;
|
||||
this.timer0Enabled = true;
|
||||
this.timer0Precounter = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.timer0Enabled = false;
|
||||
}
|
||||
this.timer0IRQ = ((data & 0x40) != 0);
|
||||
this.timer0PrescalarShifted = this.prescalarLookup[data & 0x03] | 0;
|
||||
this.timer0Prescalar = 1 << (this.timer0PrescalarShifted | 0);
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM0CNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer0Reload = data & 0xFFFF;
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM0CNT32 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer0Reload = data & 0xFFFF;
|
||||
this.timer0Control = data >> 16;
|
||||
if ((data & 0x800000) != 0) {
|
||||
if (!this.timer0Enabled) {
|
||||
this.timer0Counter = this.timer0Reload | 0;
|
||||
this.timer0Enabled = true;
|
||||
this.timer0Precounter = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.timer0Enabled = false;
|
||||
}
|
||||
this.timer0IRQ = ((data & 0x400000) != 0);
|
||||
this.timer0PrescalarShifted = this.prescalarLookup[(data >> 16) & 0x03] | 0;
|
||||
this.timer0Prescalar = 1 << (this.timer0PrescalarShifted | 0);
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM0CNT8_0 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return this.timer0Counter & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM0CNT8_1 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return (this.timer0Counter & 0xFF00) >> 8;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM0CNT8_2 = function () {
|
||||
return this.timer0Control & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM0CNT16 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return this.timer0Counter | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM0CNT32 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
var data = (this.timer0Control & 0xFF) << 16;
|
||||
data = data | this.timer0Counter;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM1CNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer1Reload = this.timer1Reload & 0xFF00;
|
||||
data = data & 0xFF;
|
||||
this.timer1Reload = this.timer1Reload | data;
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM1CNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer1Reload = this.timer1Reload & 0xFF;
|
||||
data = data & 0xFF;
|
||||
this.timer1Reload = this.timer1Reload | (data << 8);
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM1CNT8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer1Control = data & 0xFF;
|
||||
if ((data & 0x80) != 0) {
|
||||
if (!this.timer1Enabled) {
|
||||
this.timer1Counter = this.timer1Reload | 0;
|
||||
this.timer1Enabled = true;
|
||||
this.timer1Precounter = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.timer1Enabled = false;
|
||||
}
|
||||
this.timer1IRQ = ((data & 0x40) != 0);
|
||||
this.timer1CountUp = ((data & 0x4) != 0);
|
||||
this.timer1PrescalarShifted = this.prescalarLookup[data & 0x03] | 0;
|
||||
this.timer1Prescalar = 1 << (this.timer1PrescalarShifted | 0);
|
||||
this.preprocessTimer1();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM1CNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer1Reload = data & 0xFFFF;
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM1CNT32 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.IOCore.sound.audioJIT();
|
||||
this.timer1Reload = data & 0xFFFF;
|
||||
this.timer1Control = data >> 16;
|
||||
if ((data & 0x800000) != 0) {
|
||||
if (!this.timer1Enabled) {
|
||||
this.timer1Counter = this.timer1Reload | 0;
|
||||
this.timer1Enabled = true;
|
||||
this.timer1Precounter = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.timer1Enabled = false;
|
||||
}
|
||||
this.timer1IRQ = ((data & 0x400000) != 0);
|
||||
this.timer1CountUp = ((data & 0x40000) != 0);
|
||||
this.timer1PrescalarShifted = this.prescalarLookup[(data >> 16) & 0x03] | 0;
|
||||
this.timer1Prescalar = 1 << (this.timer1PrescalarShifted | 0);
|
||||
this.preprocessTimer1();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM1CNT8_0 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return this.timer1Counter & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM1CNT8_1 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return (this.timer1Counter & 0xFF00) >> 8;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM1CNT8_2 = function () {
|
||||
return this.timer1Control & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM1CNT16 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return this.timer1Counter | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM1CNT32 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
var data = (this.timer1Control & 0xFF) << 16;
|
||||
data = data | this.timer1Counter;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM2CNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer2Reload = this.timer2Reload & 0xFF00;
|
||||
data = data & 0xFF;
|
||||
this.timer2Reload = this.timer2Reload | data;
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM2CNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer2Reload = this.timer2Reload & 0xFF;
|
||||
data = data & 0xFF;
|
||||
this.timer2Reload = this.timer2Reload | (data << 8);
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM2CNT8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer2Control = data & 0xFF;
|
||||
if ((data & 0x80) != 0) {
|
||||
if (!this.timer2Enabled) {
|
||||
this.timer2Counter = this.timer2Reload | 0;
|
||||
this.timer2Enabled = true;
|
||||
this.timer2Precounter = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.timer2Enabled = false;
|
||||
}
|
||||
this.timer2IRQ = ((data & 0x40) != 0);
|
||||
this.timer2CountUp = ((data & 0x4) != 0);
|
||||
this.timer2PrescalarShifted = this.prescalarLookup[data & 0x03] | 0;
|
||||
this.timer2Prescalar = 1 << (this.timer2PrescalarShifted | 0);
|
||||
this.preprocessTimer2();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM2CNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer2Reload = data & 0xFFFF;
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM2CNT32 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer2Reload = data & 0xFFFF;
|
||||
this.timer2Control = data >> 16;
|
||||
if ((data & 0x800000) != 0) {
|
||||
if (!this.timer2Enabled) {
|
||||
this.timer2Counter = this.timer2Reload | 0;
|
||||
this.timer2Enabled = true;
|
||||
this.timer2Precounter = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.timer2Enabled = false;
|
||||
}
|
||||
this.timer2IRQ = ((data & 0x400000) != 0);
|
||||
this.timer2CountUp = ((data & 0x40000) != 0);
|
||||
this.timer2PrescalarShifted = this.prescalarLookup[(data >> 16) & 0x03] | 0;
|
||||
this.timer2Prescalar = 1 << (this.timer2PrescalarShifted | 0);
|
||||
this.preprocessTimer2();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM2CNT8_0 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return this.timer2Counter & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM2CNT8_1 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return (this.timer2Counter & 0xFF00) >> 8;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM2CNT8_2 = function () {
|
||||
return this.timer2Control & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM2CNT16 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return this.timer2Counter | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM2CNT32 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
var data = (this.timer2Control & 0xFF) << 16;
|
||||
data = data | this.timer2Counter;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM3CNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer3Reload = this.timer3Reload & 0xFF00;
|
||||
data = data & 0xFF;
|
||||
this.timer3Reload = this.timer3Reload | data;
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM3CNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer3Reload = this.timer3Reload & 0xFF;
|
||||
data = data & 0xFF;
|
||||
this.timer3Reload = this.timer3Reload | (data << 8);
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM3CNT8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer3Control = data & 0xFF;
|
||||
if ((data & 0x80) != 0) {
|
||||
if (!this.timer3Enabled) {
|
||||
this.timer3Counter = this.timer3Reload | 0;
|
||||
this.timer3Enabled = true;
|
||||
this.timer3Precounter = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.timer3Enabled = false;
|
||||
}
|
||||
this.timer3IRQ = ((data & 0x40) != 0);
|
||||
this.timer3CountUp = ((data & 0x4) != 0);
|
||||
this.timer3PrescalarShifted = this.prescalarLookup[data & 0x03] | 0;
|
||||
this.timer3Prescalar = 1 << (this.timer3PrescalarShifted | 0);
|
||||
this.preprocessTimer3();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM3CNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer3Reload = data & 0xFFFF;
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.writeTM3CNT32 = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.timer3Reload = data & 0xFFFF;
|
||||
this.timer3Control = data >> 16;
|
||||
if ((data & 0x800000) != 0) {
|
||||
if (!this.timer3Enabled) {
|
||||
this.timer3Counter = this.timer3Reload | 0;
|
||||
this.timer3Enabled = true;
|
||||
this.timer3Precounter = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.timer3Enabled = false;
|
||||
}
|
||||
this.timer3IRQ = ((data & 0x400000) != 0);
|
||||
this.timer3CountUp = ((data & 0x40000) != 0);
|
||||
this.timer3PrescalarShifted = this.prescalarLookup[(data >> 16) & 0x03] | 0;
|
||||
this.timer3Prescalar = 1 << (this.timer3PrescalarShifted | 0);
|
||||
this.preprocessTimer3();
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM3CNT8_0 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return this.timer3Counter & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM3CNT8_1 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return (this.timer3Counter & 0xFF00) >> 8;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM3CNT8_2 = function () {
|
||||
return this.timer3Control & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM3CNT16 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
return this.timer3Counter | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.readTM3CNT32 = function () {
|
||||
this.IOCore.updateTimerClocking();
|
||||
var data = (this.timer3Control & 0xFF) << 16;
|
||||
data = data | this.timer3Counter;
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.preprocessTimer1 = function () {
|
||||
this.timer1UseMainClocks = (this.timer1Enabled && !this.timer1CountUp);
|
||||
this.timer1UseChainedClocks = (this.timer1Enabled && this.timer1CountUp);
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.preprocessTimer2 = function () {
|
||||
this.timer2UseMainClocks = (this.timer2Enabled && !this.timer2CountUp);
|
||||
this.timer2UseChainedClocks = (this.timer2Enabled && this.timer2CountUp);
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.preprocessTimer3 = function () {
|
||||
this.timer3UseMainClocks = (this.timer3Enabled && !this.timer3CountUp);
|
||||
this.timer3UseChainedClocks = (this.timer3Enabled && this.timer3CountUp);
|
||||
}
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceTimer.prototype.nextTimer0OverflowBase = function () {
|
||||
var countUntilReload = (0x10000 - (this.timer0Counter | 0)) | 0;
|
||||
countUntilReload = Math.imul(countUntilReload | 0, this.timer0Prescalar | 0) | 0;
|
||||
countUntilReload = ((countUntilReload | 0) - (this.timer0Precounter | 0)) | 0;
|
||||
return countUntilReload | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer0OverflowSingle = function () {
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer0Enabled) {
|
||||
eventTime = this.nextTimer0OverflowBase() | 0;
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer0Overflow = function (numOverflows) {
|
||||
numOverflows = numOverflows | 0;
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer0Enabled) {
|
||||
numOverflows = ((numOverflows | 0) - 1) | 0;
|
||||
var countUntilReload = this.nextTimer0OverflowBase() | 0;
|
||||
var reloadClocks = (0x10000 - (this.timer0Reload | 0)) | 0;
|
||||
reloadClocks = Math.imul(reloadClocks | 0, this.timer0Prescalar | 0) | 0;
|
||||
reloadClocks = (reloadClocks | 0) * (numOverflows | 0);
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer1OverflowBase = function () {
|
||||
var countUntilReload = (0x10000 - (this.timer1Counter | 0)) | 0;
|
||||
countUntilReload = Math.imul(countUntilReload | 0, this.timer1Prescalar | 0) | 0;
|
||||
countUntilReload = ((countUntilReload | 0) - (this.timer1Precounter | 0)) | 0;
|
||||
return countUntilReload | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer1Overflow = function (numOverflows) {
|
||||
numOverflows = numOverflows | 0;
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer1Enabled) {
|
||||
var reloadClocks = (0x10000 - (this.timer1Reload | 0)) | 0;
|
||||
if (this.timer1CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer1Counter | 0)) | 0;
|
||||
reloadClocks = (reloadClocks | 0) * (numOverflows | 0);
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
eventTime = this.nextTimer0Overflow(eventTime | 0) | 0;
|
||||
}
|
||||
else {
|
||||
numOverflows = ((numOverflows | 0) - 1) | 0;
|
||||
var countUntilReload = this.nextTimer1OverflowBase() | 0;
|
||||
reloadClocks = Math.imul(reloadClocks | 0, this.timer1Prescalar | 0) | 0;
|
||||
reloadClocks = reloadClocks * numOverflows;
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer1OverflowSingle = function () {
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer1Enabled) {
|
||||
if (this.timer1CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer1Counter | 0)) | 0;
|
||||
eventTime = this.nextTimer0Overflow(countUntilReload | 0) | 0;
|
||||
}
|
||||
else {
|
||||
eventTime = this.nextTimer1OverflowBase() | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer2OverflowBase = function () {
|
||||
var countUntilReload = (0x10000 - (this.timer2Counter | 0)) | 0;
|
||||
countUntilReload = Math.imul(countUntilReload | 0, this.timer2Prescalar | 0) | 0;
|
||||
countUntilReload = ((countUntilReload | 0) - (this.timer2Precounter | 0)) | 0;
|
||||
return countUntilReload | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer2Overflow = function (numOverflows) {
|
||||
numOverflows = numOverflows | 0;
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer2Enabled) {
|
||||
var reloadClocks = (0x10000 - (this.timer2Reload | 0)) | 0;
|
||||
if (this.timer2CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer2Counter | 0)) | 0;
|
||||
reloadClocks = (reloadClocks | 0) * (numOverflows | 0);
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
eventTime = this.nextTimer1Overflow(eventTime | 0) | 0;
|
||||
}
|
||||
else {
|
||||
numOverflows = ((numOverflows | 0) - 1) | 0;
|
||||
var countUntilReload = this.nextTimer2OverflowBase() | 0;
|
||||
reloadClocks = Math.imul(reloadClocks | 0, this.timer2Prescalar | 0) | 0;
|
||||
reloadClocks = reloadClocks * numOverflows;
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer2OverflowSingle = function () {
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer2Enabled) {
|
||||
if (this.timer2CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer2Counter | 0)) | 0;
|
||||
eventTime = this.nextTimer1Overflow(countUntilReload | 0) | 0;
|
||||
}
|
||||
else {
|
||||
eventTime = this.nextTimer2OverflowBase() | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer3OverflowSingle = function () {
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer3Enabled) {
|
||||
if (this.timer3CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer3Counter | 0)) | 0;
|
||||
eventTime = this.nextTimer2Overflow(countUntilReload | 0) | 0;
|
||||
}
|
||||
else {
|
||||
eventTime = (0x10000 - (this.timer3Counter | 0)) | 0;
|
||||
eventTime = Math.imul(eventTime | 0, this.timer3Prescalar | 0) | 0;
|
||||
eventTime = ((eventTime | 0) - (this.timer3Precounter | 0)) | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceTimer.prototype.nextTimer0OverflowBase = function () {
|
||||
var countUntilReload = (0x10000 - (this.timer0Counter | 0)) | 0;
|
||||
countUntilReload = ((countUntilReload | 0) * (this.timer0Prescalar | 0)) | 0;
|
||||
countUntilReload = ((countUntilReload | 0) - (this.timer0Precounter | 0)) | 0;
|
||||
return countUntilReload | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer0OverflowSingle = function () {
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer0Enabled) {
|
||||
eventTime = this.nextTimer0OverflowBase() | 0;
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer0Overflow = function (numOverflows) {
|
||||
numOverflows = numOverflows | 0;
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer0Enabled) {
|
||||
numOverflows = ((numOverflows | 0) - 1) | 0;
|
||||
var countUntilReload = this.nextTimer0OverflowBase() | 0;
|
||||
var reloadClocks = (0x10000 - (this.timer0Reload | 0)) | 0;
|
||||
reloadClocks = ((reloadClocks | 0) * (this.timer0Prescalar | 0)) | 0;
|
||||
reloadClocks = (reloadClocks | 0) * (numOverflows | 0);
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer1OverflowBase = function () {
|
||||
var countUntilReload = (0x10000 - (this.timer1Counter | 0)) | 0;
|
||||
countUntilReload = ((countUntilReload | 0) * (this.timer1Prescalar | 0)) | 0;
|
||||
countUntilReload = ((countUntilReload | 0) - (this.timer1Precounter | 0)) | 0;
|
||||
return countUntilReload | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer1Overflow = function (numOverflows) {
|
||||
numOverflows = numOverflows | 0;
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer1Enabled) {
|
||||
var reloadClocks = (0x10000 - (this.timer1Reload | 0)) | 0;
|
||||
if (this.timer1CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer1Counter | 0)) | 0;
|
||||
reloadClocks = (reloadClocks | 0) * (numOverflows | 0);
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
eventTime = this.nextTimer0Overflow(eventTime | 0) | 0;
|
||||
}
|
||||
else {
|
||||
numOverflows = ((numOverflows | 0) - 1) | 0;
|
||||
var countUntilReload = this.nextTimer1OverflowBase() | 0;
|
||||
reloadClocks = ((reloadClocks | 0) * (this.timer1Prescalar | 0)) | 0;
|
||||
reloadClocks = reloadClocks * numOverflows;
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer1OverflowSingle = function () {
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer1Enabled) {
|
||||
if (this.timer1CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer1Counter | 0)) | 0;
|
||||
eventTime = this.nextTimer0Overflow(countUntilReload | 0) | 0;
|
||||
}
|
||||
else {
|
||||
eventTime = this.nextTimer1OverflowBase() | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer2OverflowBase = function () {
|
||||
var countUntilReload = (0x10000 - (this.timer2Counter | 0)) | 0;
|
||||
countUntilReload = ((countUntilReload | 0) * (this.timer2Prescalar | 0)) | 0;
|
||||
countUntilReload = ((countUntilReload | 0) - (this.timer2Precounter | 0)) | 0;
|
||||
return countUntilReload | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer2Overflow = function (numOverflows) {
|
||||
numOverflows = numOverflows | 0;
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer2Enabled) {
|
||||
var reloadClocks = (0x10000 - (this.timer2Reload | 0)) | 0;
|
||||
if (this.timer2CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer2Counter | 0)) | 0;
|
||||
reloadClocks = (reloadClocks | 0) * (numOverflows | 0);
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
eventTime = this.nextTimer1Overflow(eventTime | 0) | 0;
|
||||
}
|
||||
else {
|
||||
numOverflows = ((numOverflows | 0) - 1) | 0;
|
||||
var countUntilReload = this.nextTimer2OverflowBase() | 0;
|
||||
reloadClocks = ((reloadClocks | 0) * (this.timer2Prescalar | 0)) | 0;
|
||||
reloadClocks = reloadClocks * numOverflows;
|
||||
eventTime = Math.min((countUntilReload | 0) + reloadClocks, 0x7FFFFFFF) | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer2OverflowSingle = function () {
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer2Enabled) {
|
||||
if (this.timer2CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer2Counter | 0)) | 0;
|
||||
eventTime = this.nextTimer1Overflow(countUntilReload | 0) | 0;
|
||||
}
|
||||
else {
|
||||
eventTime = this.nextTimer2OverflowBase() | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer3OverflowSingle = function () {
|
||||
var eventTime = 0x7FFFFFFF;
|
||||
if (this.timer3Enabled) {
|
||||
if (this.timer3CountUp) {
|
||||
var countUntilReload = (0x10000 - (this.timer3Counter | 0)) | 0;
|
||||
eventTime = this.nextTimer2Overflow(countUntilReload | 0) | 0;
|
||||
}
|
||||
else {
|
||||
eventTime = (0x10000 - (this.timer3Counter | 0)) | 0;
|
||||
eventTime = ((eventTime | 0) * (this.timer3Prescalar | 0)) | 0;
|
||||
eventTime = ((eventTime | 0) - (this.timer3Precounter | 0)) | 0;
|
||||
}
|
||||
}
|
||||
return eventTime | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextAudioTimerOverflow = function () {
|
||||
var timer0 = this.nextTimer0OverflowSingle() | 0;
|
||||
var timer1 = this.nextTimer1OverflowSingle() | 0;
|
||||
return Math.min(timer0 | 0, timer1 | 0) | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer0IRQEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
if (this.timer0Enabled && this.timer0IRQ) {
|
||||
clocks = this.nextTimer0OverflowSingle() | 0;
|
||||
}
|
||||
return clocks | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer1IRQEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
if (this.timer1Enabled && this.timer1IRQ) {
|
||||
clocks = this.nextTimer1OverflowSingle() | 0;
|
||||
}
|
||||
return clocks | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer2IRQEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
if (this.timer2Enabled && this.timer2IRQ) {
|
||||
clocks = this.nextTimer2OverflowSingle() | 0;
|
||||
}
|
||||
return clocks | 0;
|
||||
}
|
||||
GameBoyAdvanceTimer.prototype.nextTimer3IRQEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
if (this.timer3Enabled && this.timer3IRQ) {
|
||||
clocks = this.nextTimer3OverflowSingle() | 0;
|
||||
}
|
||||
return clocks | 0;
|
||||
}
|
484
public/gfiles/gba/IodineGBA/core/Wait.js
Normal file
484
public/gfiles/gba/IodineGBA/core/Wait.js
Normal file
|
@ -0,0 +1,484 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceWait(IOCore) {
|
||||
//Build references:
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.initialize = function () {
|
||||
this.memory = this.IOCore.memory;
|
||||
this.cpu = this.IOCore.cpu;
|
||||
this.WRAMConfiguration = 0xD000020; //WRAM configuration control register current data.
|
||||
this.WRAMWaitState = 3; //External WRAM wait state.
|
||||
this.SRAMWaitState = 5; //SRAM wait state.
|
||||
this.WAITCNT0 = 0; //WAITCNT0 control register data.
|
||||
this.WAITCNT1 = 0; //WAITCNT1 control register data.
|
||||
this.POSTBOOT = 0; //POSTBOOT control register data.
|
||||
this.isRendering = 1; //Are we doing memory during screen draw?
|
||||
this.isOAMRendering = 1; //Are we doing memory during OAM draw?
|
||||
this.nonSequential = 0x10; //Non-sequential access bit-flag.
|
||||
this.buffer = 0; //Tracking of the size of the prebuffer cache.
|
||||
this.clocks = 0; //Tracking clocks for prebuffer cache.
|
||||
//Create the wait state address translation cache:
|
||||
this.waitStateClocks16 = getUint8Array(0x20);
|
||||
this.waitStateClocks32 = getUint8Array(0x20);
|
||||
//Wait State 0:
|
||||
this.setWaitState(0, 0);
|
||||
//Wait State 1:
|
||||
this.setWaitState(1, 0);
|
||||
//Wait State 2:
|
||||
this.setWaitState(2, 0);
|
||||
//Initialize out some dynamic references:
|
||||
this.getROMRead16 = this.getROMRead16NoPrefetch;
|
||||
this.getROMRead32 = this.getROMRead32NoPrefetch;
|
||||
this.CPUInternalCyclePrefetch = this.CPUInternalCycleNoPrefetch;
|
||||
this.CPUInternalSingleCyclePrefetch = this.CPUInternalSingleCycleNoPrefetch;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.getWaitStateFirstAccess = function (data) {
|
||||
//Get the first access timing:
|
||||
data = data | 0;
|
||||
data = data & 0x3;
|
||||
if ((data | 0) < 0x3) {
|
||||
data = (5 - (data | 0)) | 0;
|
||||
}
|
||||
else {
|
||||
data = 9;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.getWaitStateSecondAccess = function (region, data) {
|
||||
//Get the second access timing:
|
||||
region = region | 0;
|
||||
data = data | 0;
|
||||
if ((data & 0x4) == 0) {
|
||||
data = 0x2 << (region | 0);
|
||||
data = ((data | 0) + 1) | 0;
|
||||
}
|
||||
else {
|
||||
data = 0x2;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.setWaitState = function (region, data) {
|
||||
region = region | 0;
|
||||
data = data | 0;
|
||||
//Wait State First Access:
|
||||
var firstAccess = this.getWaitStateFirstAccess(data & 0x3) | 0;
|
||||
//Wait State Second Access:
|
||||
var secondAccess = this.getWaitStateSecondAccess(region | 0, data | 0) | 0;
|
||||
region = region << 1;
|
||||
//Computing First Access:
|
||||
//8-16 bit access:
|
||||
this.waitStateClocks16[0x18 | region] = firstAccess | 0;
|
||||
this.waitStateClocks16[0x19 | region] = firstAccess | 0;
|
||||
//32 bit access:
|
||||
var accessTime = ((firstAccess | 0) + (secondAccess | 0)) | 0;
|
||||
this.waitStateClocks32[0x18 | region] = accessTime | 0;
|
||||
this.waitStateClocks32[0x19 | region] = accessTime | 0;
|
||||
//Computing Second Access:
|
||||
//8-16 bit access:
|
||||
this.waitStateClocks16[0x8 | region] = secondAccess | 0;
|
||||
this.waitStateClocks16[0x9 | region] = secondAccess | 0;
|
||||
//32 bit access:
|
||||
this.waitStateClocks32[0x8 | region] = secondAccess << 1;
|
||||
this.waitStateClocks32[0x9 | region] = secondAccess << 1;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.writeWAITCNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
//Set SRAM Wait State:
|
||||
if ((data & 0x3) < 0x3) {
|
||||
this.SRAMWaitState = (5 - (data & 0x3)) | 0;
|
||||
}
|
||||
else {
|
||||
this.SRAMWaitState = 9;
|
||||
}
|
||||
data = data & 0xFF;
|
||||
//Set Wait State 0:
|
||||
this.setWaitState(0, data >> 2);
|
||||
//Set Wait State 1:
|
||||
this.setWaitState(1, data >> 5);
|
||||
this.WAITCNT0 = data | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.readWAITCNT8_0 = function () {
|
||||
return this.WAITCNT0 | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.writeWAITCNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
//Set Wait State 2:
|
||||
this.setWaitState(2, data & 0xFF);
|
||||
//Set Prefetch Mode:
|
||||
if ((data & 0x40) == 0) {
|
||||
//No Prefetch:
|
||||
this.resetPrebuffer();
|
||||
this.getROMRead16 = this.getROMRead16NoPrefetch;
|
||||
this.getROMRead32 = this.getROMRead32NoPrefetch;
|
||||
this.CPUInternalCyclePrefetch = this.CPUInternalCycleNoPrefetch;
|
||||
this.CPUInternalSingleCyclePrefetch = this.CPUInternalSingleCycleNoPrefetch;
|
||||
}
|
||||
else {
|
||||
//Prefetch Enabled:
|
||||
this.getROMRead16 = this.getROMRead16Prefetch;
|
||||
this.getROMRead32 = this.getROMRead32Prefetch;
|
||||
this.CPUInternalCyclePrefetch = this.multiClock;
|
||||
this.CPUInternalSingleCyclePrefetch = this.singleClock;
|
||||
}
|
||||
this.WAITCNT1 = data & 0x5F;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.readWAITCNT8_1 = function () {
|
||||
return this.WAITCNT1 | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.writeWAITCNT16 = function (data) {
|
||||
this.writeWAITCNT8_0(data | 0);
|
||||
this.writeWAITCNT8_1(data >> 8);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.readWAITCNT16 = function () {
|
||||
var data = this.WAITCNT0 | 0;
|
||||
data = data | (this.WAITCNT1 << 8);
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.writePOSTBOOT = function (data) {
|
||||
this.POSTBOOT = data & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.readPOSTBOOT = function () {
|
||||
return this.POSTBOOT | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.writeHALTCNT = function (data) {
|
||||
data = data | 0;
|
||||
this.IOCore.updateCoreSpillRetain();
|
||||
//HALT/STOP mode entrance:
|
||||
if ((data & 0x80) == 0) {
|
||||
//Halt:
|
||||
this.IOCore.flagHalt();
|
||||
}
|
||||
else {
|
||||
//Stop:
|
||||
this.IOCore.flagStop();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.writeHALT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.POSTBOOT = data & 0xFF;
|
||||
this.IOCore.updateCoreSpillRetain();
|
||||
//HALT/STOP mode entrance:
|
||||
if ((data & 0x8000) == 0) {
|
||||
//Halt:
|
||||
this.IOCore.flagHalt();
|
||||
}
|
||||
else {
|
||||
//Stop:
|
||||
this.IOCore.flagStop();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.writeConfigureWRAM8 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
switch (address & 0x3) {
|
||||
case 0:
|
||||
this.memory.remapWRAM(data & 0x21);
|
||||
this.WRAMConfiguration = (this.WRAMConfiguration & 0xFFFFFF00) | (data & 0xFF);
|
||||
break;
|
||||
case 1:
|
||||
this.WRAMConfiguration = (this.WRAMConfiguration & 0xFFFF00FF) | ((data & 0xFF) << 8);
|
||||
break;
|
||||
case 2:
|
||||
this.WRAMConfiguration = (this.WRAMConfiguration & 0xFF00FFFF) | ((data & 0xFF) << 16);
|
||||
break;
|
||||
default:
|
||||
this.WRAMWaitState = (0x10 - (data & 0xF)) | 0;
|
||||
this.WRAMConfiguration = (this.WRAMConfiguration & 0xFFFFFF) | (data << 24);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.writeConfigureWRAM16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((address & 0x2) == 0) {
|
||||
this.WRAMConfiguration = (this.WRAMConfiguration & 0xFFFF0000) | (data & 0xFFFF);
|
||||
this.memory.remapWRAM(data & 0x21);
|
||||
}
|
||||
else {
|
||||
this.WRAMConfiguration = (data << 16) | (this.WRAMConfiguration & 0xFFFF);
|
||||
this.WRAMWaitState = (0x10 - ((data >> 8) & 0xF)) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.writeConfigureWRAM32 = function (data) {
|
||||
data = data | 0;
|
||||
this.WRAMConfiguration = data | 0;
|
||||
this.WRAMWaitState = (0x10 - ((data >> 24) & 0xF)) | 0;
|
||||
this.memory.remapWRAM(data & 0x21);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.readConfigureWRAM8 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
switch (address & 0x3) {
|
||||
case 0:
|
||||
data = this.WRAMConfiguration & 0x2F;
|
||||
break;
|
||||
case 3:
|
||||
data = this.WRAMConfiguration >>> 24;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.readConfigureWRAM16 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address & 0x2) == 0) {
|
||||
data = this.WRAMConfiguration & 0x2F;
|
||||
}
|
||||
else {
|
||||
data = (this.WRAMConfiguration >> 16) & 0xFF00;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.readConfigureWRAM32 = function () {
|
||||
return this.WRAMConfiguration & 0xFF00002F;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.CPUInternalCycleNoPrefetch = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
//Clock for idle CPU time:
|
||||
this.IOCore.updateCore(clocks | 0);
|
||||
//Prebuffer bug:
|
||||
this.checkPrebufferBug();
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.CPUInternalSingleCycleNoPrefetch = function () {
|
||||
//Clock for idle CPU time:
|
||||
this.IOCore.updateCoreSingle();
|
||||
//Not enough time for prebuffer buffering, so skip it.
|
||||
//Prebuffer bug:
|
||||
this.checkPrebufferBug();
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.checkPrebufferBug = function () {
|
||||
//Issue a non-sequential cycle for the next read if we did an I-cycle:
|
||||
var address = this.cpu.registers[15] | 0;
|
||||
if ((address | 0) >= 0x8000000 && (address | 0) < 0xE000000) {
|
||||
this.NonSequentialBroadcast();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.NonSequentialBroadcast = function () {
|
||||
//Flag as N cycle:
|
||||
this.nonSequential = 0x10;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.NonSequentialBroadcastClear = function () {
|
||||
//PC branched:
|
||||
this.NonSequentialBroadcast();
|
||||
this.resetPrebuffer();
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.check128kAlignmentBug = function (address) {
|
||||
address = address | 0;
|
||||
if ((address & 0x1FFFF) == 0) {
|
||||
this.NonSequentialBroadcast();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.multiClock = function (clocks) {
|
||||
clocks = clocks | 0;
|
||||
this.IOCore.updateCore(clocks | 0);
|
||||
var address = this.cpu.registers[15] | 0;
|
||||
if ((address | 0) >= 0x8000000 && (address | 0) < 0xE000000) {
|
||||
if ((this.clocks | 0) < 0xFF) {
|
||||
this.clocks = ((this.clocks | 0) + (clocks | 0)) | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.resetPrebuffer();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.singleClock = function () {
|
||||
this.IOCore.updateCoreSingle();
|
||||
var address = this.cpu.registers[15] | 0;
|
||||
if ((address | 0) >= 0x8000000 && (address | 0) < 0xE000000) {
|
||||
if ((this.clocks | 0) < 0xFF) {
|
||||
this.clocks = ((this.clocks | 0) + 1) | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.resetPrebuffer();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.addPrebufferSingleClock = function () {
|
||||
this.clocks = ((this.clocks | 0) + 1) | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.decrementBufferSingle = function () {
|
||||
this.buffer = ((this.buffer | 0) - 1) | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.decrementBufferDouble = function () {
|
||||
this.buffer = ((this.buffer | 0) - 2) | 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.resetPrebuffer = function () {
|
||||
//Reset the buffering:
|
||||
this.clocks = 0;
|
||||
this.buffer = 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.drainOverdueClocks = function () {
|
||||
if ((this.clocks | 0) > 0 && (this.buffer | 0) < 8) {
|
||||
var address = this.cpu.registers[15] >>> 24;
|
||||
//Convert built up clocks to 16 bit word buffer units:
|
||||
do {
|
||||
this.clocks = ((this.clocks | 0) - (this.waitStateClocks16[address | 0] | 0)) | 0;
|
||||
this.buffer = ((this.buffer | 0) + 1) | 0;
|
||||
} while ((this.clocks | 0) > 0 && (this.buffer | 0) < 8);
|
||||
//If we're deficient in clocks, fit them in before the access:
|
||||
if ((this.clocks | 0) < 0) {
|
||||
this.IOCore.updateCoreNegative(this.clocks | 0);
|
||||
this.clocks = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.computeClocks = function (address) {
|
||||
address = address | 0;
|
||||
//Convert built up clocks to 16 bit word buffer units:
|
||||
while ((this.buffer | 0) < 8 && (this.clocks | 0) >= (this.waitStateClocks16[address | 0] | 0)) {
|
||||
this.clocks = ((this.clocks | 0) - (this.waitStateClocks16[address | 0] | 0)) | 0;
|
||||
this.buffer = ((this.buffer | 0) + 1) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.drainOverdueClocksCPU = function () {
|
||||
if ((this.clocks | 0) < 0) {
|
||||
//Compute "overdue" clocks:
|
||||
this.IOCore.updateCoreNegative(this.clocks | 0);
|
||||
this.clocks = 0;
|
||||
}
|
||||
else {
|
||||
//Buffer satiated, clock 1:
|
||||
this.IOCore.updateCoreSingle();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.doGamePakFetch16 = function (address) {
|
||||
address = address | 0;
|
||||
//Fetch 16 bit word into buffer:
|
||||
this.clocks = ((this.clocks | 0) - (this.waitStateClocks16[address | this.nonSequential] | 0)) | 0;
|
||||
this.nonSequential = 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.doGamePakFetch32 = function (address) {
|
||||
address = address | 0;
|
||||
//Fetch 16 bit word into buffer:
|
||||
this.clocks = ((this.clocks | 0) - (this.waitStateClocks32[address | this.nonSequential] | 0)) | 0;
|
||||
this.nonSequential = 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.getROMRead16Prefetch = function (address) {
|
||||
//Caching enabled:
|
||||
address = address | 0;
|
||||
//Resolve clocks to buffer units:
|
||||
this.computeClocks(address | 0);
|
||||
//Need 16 bits minimum buffered:
|
||||
switch (this.buffer | 0) {
|
||||
case 0:
|
||||
//Fetch 16 bit word into buffer:
|
||||
this.doGamePakFetch16(address | 0);
|
||||
break;
|
||||
default:
|
||||
//Instruction fetch is 1 clock wide minimum:
|
||||
this.addPrebufferSingleClock();
|
||||
//Decrement the buffer:
|
||||
this.decrementBufferSingle();
|
||||
}
|
||||
//Clock the state:
|
||||
this.drainOverdueClocksCPU();
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.getROMRead16NoPrefetch = function (address) {
|
||||
//Caching disabled:
|
||||
address = address | 0;
|
||||
this.IOCore.updateCore(this.waitStateClocks16[address | this.nonSequential] | 0);
|
||||
this.nonSequential = 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.getROMRead32Prefetch = function (address) {
|
||||
//Caching enabled:
|
||||
address = address | 0;
|
||||
//Resolve clocks to buffer units:
|
||||
this.computeClocks(address | 0);
|
||||
//Need 32 bits minimum buffered:
|
||||
switch (this.buffer | 0) {
|
||||
case 0:
|
||||
//Fetch two 16 bit words into buffer:
|
||||
this.doGamePakFetch32(address | 0);
|
||||
break;
|
||||
case 1:
|
||||
//Fetch a 16 bit word into buffer:
|
||||
this.doGamePakFetch16(address | 0);
|
||||
this.buffer = 0;
|
||||
break;
|
||||
default:
|
||||
//Instruction fetch is 1 clock wide minimum:
|
||||
this.addPrebufferSingleClock();
|
||||
//Decrement the buffer:
|
||||
this.decrementBufferDouble();
|
||||
}
|
||||
//Clock the state:
|
||||
this.drainOverdueClocksCPU();
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.getROMRead32NoPrefetch = function (address) {
|
||||
//Caching disabled:
|
||||
address = address | 0;
|
||||
this.IOCore.updateCore(this.waitStateClocks32[address | this.nonSequential] | 0);
|
||||
this.nonSequential = 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.WRAMAccess = function () {
|
||||
this.multiClock(this.WRAMWaitState | 0);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.WRAMAccess16CPU = function () {
|
||||
this.IOCore.updateCore(this.WRAMWaitState | 0);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.WRAMAccess32 = function () {
|
||||
this.multiClock(this.WRAMWaitState << 1);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.WRAMAccess32CPU = function () {
|
||||
this.IOCore.updateCore(this.WRAMWaitState << 1);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.ROMAccess = function (address) {
|
||||
address = address | 0;
|
||||
this.drainOverdueClocks();
|
||||
this.check128kAlignmentBug(address | 0);
|
||||
this.IOCore.updateCore(this.waitStateClocks16[(address >> 24) | this.nonSequential] | 0);
|
||||
this.nonSequential = 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.ROMAccess16CPU = function (address) {
|
||||
address = address | 0;
|
||||
this.check128kAlignmentBug(address | 0);
|
||||
this.getROMRead16(address >> 24);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.ROMAccess32 = function (address) {
|
||||
address = address | 0;
|
||||
this.drainOverdueClocks();
|
||||
this.check128kAlignmentBug(address | 0);
|
||||
this.IOCore.updateCore(this.waitStateClocks32[(address >> 24) | this.nonSequential] | 0);
|
||||
this.nonSequential = 0;
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.ROMAccess32CPU = function (address) {
|
||||
address = address | 0;
|
||||
this.check128kAlignmentBug(address | 0);
|
||||
this.getROMRead32(address >> 24);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.SRAMAccess = function () {
|
||||
this.multiClock(this.SRAMWaitState | 0);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.SRAMAccessCPU = function () {
|
||||
this.resetPrebuffer();
|
||||
this.IOCore.updateCore(this.SRAMWaitState | 0);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.VRAMAccess = function () {
|
||||
this.multiClock(this.isRendering | 0);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.VRAMAccess16CPU = function () {
|
||||
this.IOCore.updateCore(this.isRendering | 0);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.VRAMAccess32 = function () {
|
||||
this.multiClock(this.isRendering << 1);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.VRAMAccess32CPU = function () {
|
||||
this.IOCore.updateCore(this.isRendering << 1);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.OAMAccess = function () {
|
||||
this.multiClock(this.isOAMRendering | 0);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.OAMAccessCPU = function () {
|
||||
this.IOCore.updateCore(this.isOAMRendering | 0);
|
||||
}
|
||||
GameBoyAdvanceWait.prototype.updateRenderStatus = function (isRendering, isOAMRendering) {
|
||||
this.isRendering = isRendering | 0;
|
||||
this.isOAMRendering = isOAMRendering | 0;
|
||||
}
|
300
public/gfiles/gba/IodineGBA/core/Worker.js
Normal file
300
public/gfiles/gba/IodineGBA/core/Worker.js
Normal file
|
@ -0,0 +1,300 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2019 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
importScripts("../includes/TypedArrayShim.js");
|
||||
importScripts("Cartridge.js");
|
||||
importScripts("DMA.js");
|
||||
importScripts("Emulator.js");
|
||||
importScripts("Graphics.js");
|
||||
importScripts("RunLoop.js");
|
||||
importScripts("Memory.js");
|
||||
importScripts("IRQ.js");
|
||||
importScripts("JoyPad.js");
|
||||
importScripts("Serial.js");
|
||||
importScripts("Sound.js");
|
||||
importScripts("Timer.js");
|
||||
importScripts("Wait.js");
|
||||
importScripts("CPU.js");
|
||||
importScripts("Saves.js");
|
||||
importScripts("sound/FIFO.js");
|
||||
importScripts("sound/Channel1.js");
|
||||
importScripts("sound/Channel2.js");
|
||||
importScripts("sound/Channel3.js");
|
||||
importScripts("sound/Channel4.js");
|
||||
importScripts("CPU/ARM.js");
|
||||
importScripts("CPU/THUMB.js");
|
||||
importScripts("CPU/CPSR.js");
|
||||
importScripts("graphics/RendererProxy.js");
|
||||
importScripts("graphics/RendererShim.js");
|
||||
importScripts("graphics/Renderer.js");
|
||||
importScripts("graphics/BGTEXT.js");
|
||||
importScripts("graphics/BG2FrameBuffer.js");
|
||||
importScripts("graphics/BGMatrix.js");
|
||||
importScripts("graphics/AffineBG.js");
|
||||
importScripts("graphics/ColorEffects.js");
|
||||
importScripts("graphics/Mosaic.js");
|
||||
importScripts("graphics/OBJ.js");
|
||||
importScripts("graphics/OBJWindow.js");
|
||||
importScripts("graphics/Window.js");
|
||||
importScripts("graphics/Compositor.js");
|
||||
importScripts("memory/DMA0.js");
|
||||
importScripts("memory/DMA1.js");
|
||||
importScripts("memory/DMA2.js");
|
||||
importScripts("memory/DMA3.js");
|
||||
importScripts("cartridge/SaveDeterminer.js");
|
||||
importScripts("cartridge/SRAM.js");
|
||||
importScripts("cartridge/FLASH.js");
|
||||
importScripts("cartridge/EEPROM.js");
|
||||
importScripts("cartridge/GPIO.js");
|
||||
var Iodine = new GameBoyAdvanceEmulator();
|
||||
//Save callbacks waiting to be satisfied:
|
||||
var saveImportPool = [];
|
||||
//Graphics Buffers:
|
||||
var gfxBuffers = [getSharedUint8Array(160 * 240 * 3),
|
||||
getSharedUint8Array(160 * 240 * 3)];
|
||||
var gfxCounters = getSharedInt32Array(3);
|
||||
//Audio Buffers:
|
||||
var audioBuffer = null;
|
||||
var audioCounters = null;
|
||||
var audioBufferSize = 0;
|
||||
var audioBufferSizeMask = 0;
|
||||
var audioSamplesRemaining = getSharedInt32Array(1);
|
||||
//Time Stamp tracking:
|
||||
var timestamp = getSharedUint32Array(1);
|
||||
//Interval Timer handle:
|
||||
var timerHandle = null;
|
||||
var timerRate = 0;
|
||||
//Pass the shared array buffers:
|
||||
try {
|
||||
postMessage({messageID:0, gfxBuffer1:gfxBuffers[0], gfxBuffer2:gfxBuffers[1], gfxCounters:gfxCounters, audioSamplesRemaining:audioSamplesRemaining, timestamp:timestamp}, [gfxBuffers[0].buffer, gfxBuffers[1].buffer, gfxCounters.buffer, audioSamplesRemaining.buffer, timestamp.buffer]);
|
||||
}
|
||||
catch (e) {
|
||||
postMessage({messageID:0, gfxBuffer1:gfxBuffers[0], gfxBuffer2:gfxBuffers[1], gfxCounters:gfxCounters, audioSamplesRemaining:audioSamplesRemaining, timestamp:timestamp});
|
||||
}
|
||||
//Event decoding:
|
||||
self.onmessage = function (event) {
|
||||
var data = event.data;
|
||||
switch (data.messageID | 0) {
|
||||
case 0:
|
||||
Iodine.play();
|
||||
break;
|
||||
case 1:
|
||||
Iodine.pause();
|
||||
break;
|
||||
case 2:
|
||||
Iodine.restart();
|
||||
break;
|
||||
case 3:
|
||||
Iodine.setIntervalRate(+data.payload);
|
||||
changeTimer(data.payload | 0);
|
||||
break;
|
||||
case 4:
|
||||
Iodine.attachGraphicsFrameHandler(graphicsFrameHandler);
|
||||
break;
|
||||
case 5:
|
||||
Iodine.attachAudioHandler(audioHandler);
|
||||
break;
|
||||
case 6:
|
||||
Iodine.enableAudio();
|
||||
break;
|
||||
case 7:
|
||||
Iodine.disableAudio();
|
||||
break;
|
||||
case 8:
|
||||
Iodine.toggleSkipBootROM(!!data.payload);
|
||||
break;
|
||||
case 9:
|
||||
Iodine.toggleDynamicSpeed(!!data.payload);
|
||||
break;
|
||||
case 10:
|
||||
Iodine.attachSpeedHandler(speedHandler);
|
||||
break;
|
||||
case 11:
|
||||
Iodine.keyDown(data.payload | 0);
|
||||
break;
|
||||
case 12:
|
||||
Iodine.keyUp(data.payload | 0);
|
||||
break;
|
||||
case 13:
|
||||
Iodine.incrementSpeed(+data.payload);
|
||||
break;
|
||||
case 14:
|
||||
Iodine.setSpeed(+data.payload);
|
||||
break;
|
||||
case 15:
|
||||
Iodine.attachBIOS(data.payload);
|
||||
break;
|
||||
case 16:
|
||||
Iodine.attachROM(data.payload);
|
||||
break;
|
||||
case 17:
|
||||
Iodine.exportSave();
|
||||
break;
|
||||
case 18:
|
||||
Iodine.attachSaveExportHandler(saveExportHandler);
|
||||
break;
|
||||
case 19:
|
||||
Iodine.attachSaveImportHandler(saveImportHandler);
|
||||
break;
|
||||
case 20:
|
||||
processSaveImportSuccess(data.payload);
|
||||
break;
|
||||
case 21:
|
||||
processSaveImportFail();
|
||||
break;
|
||||
case 22:
|
||||
Iodine.toggleOffthreadGraphics(!!data.payload);
|
||||
break;
|
||||
case 23:
|
||||
Iodine.attachPlayStatusHandler(playStatusHandler);
|
||||
}
|
||||
}
|
||||
var graphicsFrameHandler = {
|
||||
//Function only called if graphics is THIS thread:
|
||||
copyBuffer:function (swizzledFrame) {
|
||||
//Push a frame of graphics to the blitter handle:
|
||||
//Load the counter values:
|
||||
var start = gfxCounters[0] | 0; //Written by the other thread.
|
||||
var end = gfxCounters[1] | 0; //Written by this thread.
|
||||
//Check if buffer is full:
|
||||
if ((end | 0) == (((start | 0) + 2) | 0)) {
|
||||
//Skip copying a frame out:
|
||||
return;
|
||||
}
|
||||
//Copy samples into the ring buffer:
|
||||
//Hardcoded for 2 buffers for a triple buffer effect:
|
||||
gfxBuffers[end & 0x1].set(swizzledFrame);
|
||||
//Increment the ending position counter by 1:
|
||||
//Atomic to commit the counter to memory:
|
||||
Atomics.store(gfxCounters, 1, ((end | 0) + 1) | 0);
|
||||
}
|
||||
};
|
||||
//Shim for our audio api:
|
||||
var audioHandler = {
|
||||
initialize:function (channels, sampleRate, bufferLimit, call1, call2, call3) {
|
||||
//Initialize the audio mixer input:
|
||||
channels = channels | 0;
|
||||
sampleRate = +sampleRate;
|
||||
bufferLimit = bufferLimit | 0;
|
||||
//Generate an audio buffer:
|
||||
audioBufferSize = ((bufferLimit | 0) * (channels | 0)) | 0;
|
||||
audioBufferSizeMask = 1;
|
||||
while ((audioBufferSize | 0) >= (audioBufferSizeMask | 0)) {
|
||||
audioBufferSizeMask = (audioBufferSizeMask << 1) | 1;
|
||||
}
|
||||
audioBufferSize = ((audioBufferSizeMask | 0) + 1) | 0;
|
||||
audioBuffer = getSharedFloat32Array(audioBufferSize | 0);
|
||||
audioCounters = getSharedInt32Array(2);
|
||||
try {
|
||||
postMessage({messageID:1, channels:channels | 0, sampleRate:+sampleRate, bufferLimit:bufferLimit | 0, audioBuffer:audioBuffer, audioCounters:audioCounters}, [audioBuffer.buffer, audioCounters.buffer]);
|
||||
}
|
||||
catch (e) {
|
||||
postMessage({messageID:1, channels:channels | 0, sampleRate:+sampleRate, bufferLimit:bufferLimit | 0, audioBuffer:audioBuffer, audioCounters:audioCounters});
|
||||
}
|
||||
},
|
||||
push:function (buffer, startPos, endPos) {
|
||||
startPos = startPos | 0;
|
||||
endPos = endPos | 0;
|
||||
//Push audio to the audio mixer input handle:
|
||||
//Load the counter values:
|
||||
var start = audioCounters[0] | 0; //Written to by the other thread.
|
||||
var end = audioCounters[1] | 0; //Written by this thread.
|
||||
var endCorrected = ((end | 0) & (audioBufferSizeMask | 0)) | 0;
|
||||
var freeBufferSpace = ((end | 0) - (start | 0)) | 0;
|
||||
freeBufferSpace = ((audioBufferSize | 0) - (freeBufferSpace | 0)) | 0;
|
||||
var amountToSend = ((endPos | 0) - (startPos | 0)) | 0;
|
||||
amountToSend = Math.min(amountToSend | 0, freeBufferSpace | 0) | 0;
|
||||
endPos = ((startPos | 0) + (amountToSend | 0)) | 0;
|
||||
//Push audio into buffer:
|
||||
for (; (startPos | 0) < (endPos | 0); startPos = ((startPos | 0) + 1) | 0) {
|
||||
audioBuffer[endCorrected | 0] = +buffer[startPos | 0];
|
||||
endCorrected = ((endCorrected | 0) + 1) | 0;
|
||||
if ((endCorrected | 0) == (audioBufferSize | 0)) {
|
||||
endCorrected = 0;
|
||||
}
|
||||
}
|
||||
//Update the cross thread buffering count:
|
||||
end = ((end | 0) + (amountToSend | 0)) | 0;
|
||||
//Atomic store to commit writes to memory:
|
||||
Atomics.store(audioCounters, 1, end | 0);
|
||||
},
|
||||
register:function () {
|
||||
//Register into the audio mixer:
|
||||
postMessage({messageID:2});
|
||||
},
|
||||
unregister:function () {
|
||||
//Unregister from audio mixer:
|
||||
postMessage({messageID:3});
|
||||
},
|
||||
setBufferSpace:function (spaceContain) {
|
||||
//Ensure buffering minimum levels for the audio:
|
||||
postMessage({messageID:4, audioBufferContainAmount:spaceContain | 0});
|
||||
},
|
||||
remainingBuffer:function () {
|
||||
//Report the amount of audio samples in-flight:
|
||||
var ringBufferCount = this.remainingBufferShared() | 0;
|
||||
var audioSysCount = audioSamplesRemaining[0] | 0;
|
||||
return ((ringBufferCount | 0) + (audioSysCount | 0)) | 0;
|
||||
},
|
||||
remainingBufferShared:function () {
|
||||
//Reported the sample count left in the shared buffer:
|
||||
var start = audioCounters[0] | 0;
|
||||
var end = audioCounters[1] | 0;
|
||||
var ringBufferCount = ((end | 0) - (start | 0)) | 0;
|
||||
return ringBufferCount | 0;
|
||||
}
|
||||
};
|
||||
function saveImportHandler(saveID, saveCallback, noSaveCallback) {
|
||||
postMessage({messageID:5, saveID:saveID});
|
||||
saveImportPool.push([saveCallback, noSaveCallback]);
|
||||
}
|
||||
function saveExportHandler(saveID, saveData) {
|
||||
postMessage({messageID:6, saveID:saveID, saveData:saveData});
|
||||
}
|
||||
function speedHandler(speed) {
|
||||
postMessage({messageID:7, speed:speed});
|
||||
}
|
||||
function processSaveImportSuccess(saveData) {
|
||||
saveImportPool.shift()[0](saveData);
|
||||
}
|
||||
function processSaveImportFail() {
|
||||
saveImportPool.shift()[1]();
|
||||
}
|
||||
function playStatusHandler(isPlaying) {
|
||||
isPlaying = isPlaying | 0;
|
||||
postMessage({messageID:8, playing:(isPlaying | 0)});
|
||||
if ((isPlaying | 0) == 0) {
|
||||
if (timerHandle) {
|
||||
clearInterval(timerHandle);
|
||||
timerHandle = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!timerHandle) {
|
||||
initTimer(timerRate | 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
function changeTimer(rate) {
|
||||
rate = rate | 0;
|
||||
if (timerHandle) {
|
||||
clearInterval(timerHandle);
|
||||
initTimer(rate | 0);
|
||||
}
|
||||
timerRate = rate | 0;
|
||||
}
|
||||
function initTimer(rate) {
|
||||
rate = rate | 0;
|
||||
if ((rate | 0) > 0) {
|
||||
timerHandle = setInterval(function() {
|
||||
Iodine.timerCallback(timestamp[0] >>> 0);
|
||||
}, rate | 0);
|
||||
}
|
||||
}
|
190
public/gfiles/gba/IodineGBA/core/cartridge/EEPROM.js
Normal file
190
public/gfiles/gba/IodineGBA/core/cartridge/EEPROM.js
Normal file
|
@ -0,0 +1,190 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceEEPROMChip(IOCore) {
|
||||
this.saves = null;
|
||||
this.largestSizePossible = 0x200;
|
||||
this.mode = 0;
|
||||
this.bitsProcessed = 0;
|
||||
this.address = 0;
|
||||
this.buffer = getUint8Array(8);
|
||||
this.IOCore = IOCore;
|
||||
//Special note to emulator authors: EEPROM command ending bit "0" can also be a "1"...
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.initialize = function () {
|
||||
this.allocate();
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.allocate = function () {
|
||||
if (this.saves == null || (this.saves.length | 0) < (this.largestSizePossible | 0)) {
|
||||
//Allocate the new array:
|
||||
var newSave = getUint8Array(this.largestSizePossible | 0);
|
||||
//Init to default value:
|
||||
for (var index = 0; (index | 0) < (this.largestSizePossible | 0); index = ((index | 0) + 1) | 0) {
|
||||
newSave[index | 0] = 0xFF;
|
||||
}
|
||||
//Copy the old save data out:
|
||||
if (this.saves != null) {
|
||||
for (var index = 0; (index | 0) < (this.saves.length | 0); index = ((index | 0) + 1) | 0) {
|
||||
newSave[index | 0] = this.saves[index | 0] | 0;
|
||||
}
|
||||
}
|
||||
//Assign the new array out:
|
||||
this.saves = newSave;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.load = function (save) {
|
||||
if ((save.length | 0) == 0x200 || (save.length | 0) == 0x2000) {
|
||||
this.saves = save;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.read8 = function () {
|
||||
//Can't do real reading with 8-bit reads:
|
||||
return 0x1;
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.read16 = function () {
|
||||
var data = 1;
|
||||
switch (this.mode | 0) {
|
||||
case 0x7:
|
||||
//Return 4 junk 0 bits:
|
||||
data = 0;
|
||||
if ((this.bitsProcessed | 0) < 3) {
|
||||
//Increment our bits counter:
|
||||
this.bitsProcessed = ((this.bitsProcessed | 0) + 1) | 0;
|
||||
}
|
||||
else {
|
||||
//Reset our bits counter:
|
||||
this.bitsProcessed = 0;
|
||||
//Change mode for the actual reads:
|
||||
this.mode = 8;
|
||||
}
|
||||
break;
|
||||
case 0x8:
|
||||
//Return actual serial style data:
|
||||
var address = ((this.bitsProcessed >> 3) + (this.address | 0)) | 0;
|
||||
data = (this.saves[address | 0] >> ((0x7 - (this.bitsProcessed & 0x7)) | 0)) & 0x1;
|
||||
//Check for end of read:
|
||||
if ((this.bitsProcessed | 0) < 0x3F) {
|
||||
//Increment our bits counter:
|
||||
this.bitsProcessed = ((this.bitsProcessed | 0) + 1) | 0;
|
||||
}
|
||||
else {
|
||||
//Finished read and now idle:
|
||||
this.resetMode();
|
||||
}
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.read32 = function () {
|
||||
//Can't do real reading with 32-bit reads:
|
||||
return 0x10001;
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.write16 = function (data) {
|
||||
data = data | 0;
|
||||
data = data & 0x1;
|
||||
//Writes only work in DMA:
|
||||
switch (this.mode | 0) {
|
||||
//Idle Mode:
|
||||
case 0:
|
||||
this.mode = data | 0;
|
||||
break;
|
||||
//Select Mode:
|
||||
case 0x1:
|
||||
this.selectMode(data | 0);
|
||||
break;
|
||||
//Address Mode (Write):
|
||||
case 0x2:
|
||||
//Address Mode (Read):
|
||||
case 0x3:
|
||||
this.addressMode(data | 0);
|
||||
break;
|
||||
//Write Mode:
|
||||
case 0x4:
|
||||
this.writeMode(data | 0);
|
||||
break;
|
||||
//Ending bit of addressing:
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
this.endAddressing();
|
||||
break;
|
||||
//Read Mode:
|
||||
default:
|
||||
this.resetMode();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.selectMode = function (data) {
|
||||
data = data | 0;
|
||||
//Reset our address:
|
||||
this.address = 0;
|
||||
//Reset our bits counter:
|
||||
this.bitsProcessed = 0;
|
||||
//Read the mode bit:
|
||||
this.mode = 0x2 | data;
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.addressMode = function (data) {
|
||||
data = data | 0;
|
||||
//Shift in our address bit:
|
||||
this.address = (this.address << 1) | data;
|
||||
//Increment our bits counter:
|
||||
this.bitsProcessed = ((this.bitsProcessed | 0) + 1) | 0;
|
||||
//Check for how many bits we've shifted in:
|
||||
switch (this.bitsProcessed | 0) {
|
||||
//6 bit address mode:
|
||||
case 0x6:
|
||||
if ((this.IOCore.dmaChannel3.wordCountShadow | 0) >= (((this.mode | 0) == 2) ? 0x4A : 0xA)) {
|
||||
this.largestSizePossible = 0x2000;
|
||||
this.allocate();
|
||||
break;
|
||||
}
|
||||
//14 bit address mode:
|
||||
case 0xE:
|
||||
this.changeModeToActive();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.changeModeToActive = function () {
|
||||
//Ensure the address range:
|
||||
this.address &= 0x3FF;
|
||||
//Addressing in units of 8 bytes:
|
||||
this.address <<= 3;
|
||||
//Reset our bits counter:
|
||||
this.bitsProcessed = 0;
|
||||
//Change to R/W Mode:
|
||||
this.mode = ((this.mode | 0) + 2) | 0;
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.writeMode = function (data) {
|
||||
data = data | 0;
|
||||
//Push a bit into the buffer:
|
||||
this.pushBuffer(data | 0);
|
||||
//Save on last write bit push:
|
||||
if ((this.bitsProcessed | 0) == 0x40) {
|
||||
//64 bits buffered, so copy our buffer to the save data:
|
||||
this.copyBuffer();
|
||||
this.mode = 6;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.pushBuffer = function (data) {
|
||||
data = data | 0;
|
||||
//Push a bit through our serial buffer:
|
||||
var bufferPosition = this.bitsProcessed >> 3;
|
||||
this.buffer[bufferPosition & 0x7] = ((this.buffer[bufferPosition & 0x7] << 1) & 0xFE) | data;
|
||||
this.bitsProcessed = ((this.bitsProcessed | 0) + 1) | 0;
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.copyBuffer = function () {
|
||||
//Copy 8 bytes from buffer to EEPROM save data starting at address offset:
|
||||
for (var index = 0; (index | 0) < 8; index = ((index | 0) + 1) | 0) {
|
||||
this.saves[this.address | index] = this.buffer[index & 0x7] & 0xFF;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.endAddressing = function () {
|
||||
this.mode = ((this.mode | 0) + 2) | 0;
|
||||
}
|
||||
GameBoyAdvanceEEPROMChip.prototype.resetMode = function () {
|
||||
//Reset back to idle:
|
||||
this.mode = 0;
|
||||
}
|
210
public/gfiles/gba/IodineGBA/core/cartridge/FLASH.js
Normal file
210
public/gfiles/gba/IodineGBA/core/cartridge/FLASH.js
Normal file
|
@ -0,0 +1,210 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2013 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceFLASHChip(is128, isAteml) {
|
||||
this.largestSizePossible = (!!is128) ? 0x20000 : 0x10000;
|
||||
this.notATMEL = !isAteml;
|
||||
this.saves = null;
|
||||
this.BANKOffset = 0;
|
||||
this.flashCommandUnlockStage = 0;
|
||||
this.flashCommand = 0;
|
||||
this.writeBytesLeft = 0;
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.initialize = function () {
|
||||
this.allocate();
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.allocate = function () {
|
||||
if (this.saves == null || (this.saves.length | 0) < (this.largestSizePossible | 0)) {
|
||||
//Allocate the new array:
|
||||
var newSave = getUint8Array(this.largestSizePossible | 0);
|
||||
//Init to default value:
|
||||
for (var index = 0; (index | 0) < (this.largestSizePossible | 0); index = ((index | 0) + 1) | 0) {
|
||||
newSave[index | 0] = 0xFF;
|
||||
}
|
||||
//Copy the old save data out:
|
||||
if (this.saves != null) {
|
||||
for (var index = 0; (index | 0) < (this.saves.length | 0); index = ((index | 0) + 1) | 0) {
|
||||
newSave[index | 0] = this.saves[index | 0] | 0;
|
||||
}
|
||||
}
|
||||
//Assign the new array out:
|
||||
this.saves = newSave;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.load = function (save) {
|
||||
if ((save.length | 0) == 0x10000 || (save.length | 0) == 0x20000) {
|
||||
this.saves = save;
|
||||
if ((save.length | 0) == 0x20000) {
|
||||
this.notATMEL = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.read = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.flashCommand | 0) != 2 || (address | 0) > 1) {
|
||||
data = this.saves[address | this.BANKOffset] | 0;
|
||||
}
|
||||
else {
|
||||
if ((address | 0) == 0) {
|
||||
if (this.notATMEL) {
|
||||
data = ((this.largestSizePossible | 0) == 0x20000) ? 0x62 : 0xBF;
|
||||
}
|
||||
else {
|
||||
data = 0x1F;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.notATMEL) {
|
||||
data = ((this.largestSizePossible | 0) == 0x20000) ? 0x13 : 0xD4;
|
||||
}
|
||||
else {
|
||||
data = 0x3D;
|
||||
}
|
||||
}
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.write = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
switch (this.writeBytesLeft | 0) {
|
||||
case 0:
|
||||
this.writeControlBits(address | 0, data | 0);
|
||||
break;
|
||||
case 0x80:
|
||||
var addressToErase = (address & 0xFF80) | this.BANKOffset;
|
||||
for (var index = 0; (index | 0) < 0x80; index = ((index | 0) + 1) | 0) {
|
||||
this.saves[addressToErase | index] = 0xFF;
|
||||
}
|
||||
default:
|
||||
this.writeByte(address | 0, data | 0);
|
||||
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.writeControlBits = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
switch (address | 0) {
|
||||
case 0:
|
||||
this.sectorEraseOrBankSwitch(address | 0, data | 0);
|
||||
break;
|
||||
case 0x5555:
|
||||
this.controlWriteStage2(data | 0);
|
||||
break;
|
||||
case 0x2AAA:
|
||||
this.controlWriteStageIncrement(data | 0);
|
||||
break;
|
||||
default:
|
||||
this.sectorErase(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.writeByte = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
this.saves[address | this.BANKOffset] = data | 0;
|
||||
this.writeBytesLeft = ((this.writeBytesLeft | 0) - 1) | 0;
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.selectBank = function (bankNumber) {
|
||||
bankNumber = bankNumber | 0;
|
||||
this.BANKOffset = (bankNumber & 0x1) << 16;
|
||||
this.largestSizePossible = Math.max((0x10000 + (this.BANKOffset | 0)) | 0, this.largestSizePossible | 0) | 0;
|
||||
this.notATMEL = true;
|
||||
this.allocate();
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.controlWriteStage2 = function (data) {
|
||||
data = data | 0;
|
||||
if ((data | 0) == 0xAA) {
|
||||
//Initial Command:
|
||||
this.flashCommandUnlockStage = 1;
|
||||
}
|
||||
else if ((this.flashCommandUnlockStage | 0) == 2) {
|
||||
switch (data | 0) {
|
||||
case 0x10:
|
||||
//Command Erase Chip:
|
||||
if ((this.flashCommand | 0) == 1) {
|
||||
for (var index = 0; (index | 0) < (this.largestSizePossible | 0); index = ((index | 0) + 1) | 0) {
|
||||
this.saves[index | 0] = 0xFF;
|
||||
}
|
||||
}
|
||||
this.flashCommand = 0;
|
||||
break;
|
||||
case 0x80:
|
||||
//Command Erase:
|
||||
this.flashCommand = 1;
|
||||
break;
|
||||
case 0x90:
|
||||
//Command ID:
|
||||
this.flashCommand = 2;
|
||||
break;
|
||||
case 0xA0:
|
||||
//Command Write:
|
||||
this.writeCommandTrigger();
|
||||
break;
|
||||
case 0xB0:
|
||||
//Command Bank Switch:
|
||||
this.flashCommand = 3;
|
||||
break;
|
||||
default:
|
||||
this.flashCommand = 0;
|
||||
}
|
||||
//Reset the command state:
|
||||
this.flashCommandUnlockStage = 0;
|
||||
}
|
||||
else if ((data | 0) == 0xF0) {
|
||||
//Command Clear:
|
||||
this.flashCommand = 0;
|
||||
this.flashCommandUnlockStage = 0;
|
||||
this.notATMEL = true;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.writeCommandTrigger = function () {
|
||||
if ((this.flashCommandUnlockStage | 0) == 2) {
|
||||
if (this.notATMEL) {
|
||||
this.writeBytesLeft = 1;
|
||||
}
|
||||
else {
|
||||
this.writeBytesLeft = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.sectorErase = function (address, data) {
|
||||
address = (address << 12) >> 12;
|
||||
data = data | 0;
|
||||
if ((this.flashCommand | 0) == 1 && (this.flashCommandUnlockStage | 0) == 2 && ((data | 0) == 0x30)) {
|
||||
var addressEnd = ((address | this.BANKOffset) + 0x1000) | 0;
|
||||
for (var index = address | this.BANKOffset; (index | 0) < (addressEnd | 0); index = ((index | 0) + 1) | 0) {
|
||||
this.saves[index | 0] = 0xFF;
|
||||
}
|
||||
this.notATMEL = true;
|
||||
}
|
||||
this.flashCommand = 0;
|
||||
this.flashCommandUnlockStage = 0;
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.sectorEraseOrBankSwitch = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((this.flashCommandUnlockStage | 0) == 2) {
|
||||
this.sectorErase(address | 0, data | 0);
|
||||
}
|
||||
else if ((this.flashCommand | 0) == 3 && (this.flashCommandUnlockStage | 0) == 0) {
|
||||
this.selectBank(data & 0x1);
|
||||
}
|
||||
this.flashCommand = 0;
|
||||
this.flashCommandUnlockStage = 0;
|
||||
}
|
||||
GameBoyAdvanceFLASHChip.prototype.controlWriteStageIncrement = function (data) {
|
||||
if ((data | 0) == 0x55 && (this.flashCommandUnlockStage | 0) == 1) {
|
||||
this.flashCommandUnlockStage = ((this.flashCommandUnlockStage | 0) + 1) | 0;
|
||||
}
|
||||
else {
|
||||
this.flashCommandUnlockStage = 0;
|
||||
}
|
||||
}
|
56
public/gfiles/gba/IodineGBA/core/cartridge/GPIO.js
Normal file
56
public/gfiles/gba/IodineGBA/core/cartridge/GPIO.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceGPIOChip() {
|
||||
this.type = 0;
|
||||
this.data = 0;
|
||||
this.direction = 0;
|
||||
this.readWrite = 0;
|
||||
}
|
||||
GameBoyAdvanceGPIOChip.prototype.getType = function () {
|
||||
return this.type | 0;
|
||||
}
|
||||
GameBoyAdvanceGPIOChip.prototype.setType = function (type) {
|
||||
type = type | 0;
|
||||
this.type = type | 0;
|
||||
}
|
||||
GameBoyAdvanceGPIOChip.prototype.read = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if (this.readWrite | 0) {
|
||||
switch (address & 0xF) {
|
||||
case 0x4:
|
||||
this.readTick();
|
||||
data = this.data | 0;
|
||||
break;
|
||||
case 0x6:
|
||||
data = this.direction | 0;
|
||||
break;
|
||||
case 0x8:
|
||||
data = this.readWrite | 0;
|
||||
}
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceGPIOChip.prototype.write = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
switch (address & 0xF) {
|
||||
case 0x4:
|
||||
this.data = data & 0xF;
|
||||
this.writeTick(data | 0);
|
||||
break;
|
||||
case 0x6:
|
||||
this.direction = data & 0xF;
|
||||
break;
|
||||
case 0x8:
|
||||
this.readWrite = data & 0x1;
|
||||
}
|
||||
}
|
85
public/gfiles/gba/IodineGBA/core/cartridge/SRAM.js
Normal file
85
public/gfiles/gba/IodineGBA/core/cartridge/SRAM.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2013 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceSRAMChip() {
|
||||
this.saves = null;
|
||||
this.TILTChip = null;
|
||||
this.TILTChipUnlocked = 0;
|
||||
}
|
||||
GameBoyAdvanceSRAMChip.prototype.initialize = function () {
|
||||
if (this.saves == null || (this.saves.length | 0) != 0x8000) {
|
||||
this.saves = getUint8Array(0x8000);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSRAMChip.prototype.load = function (save) {
|
||||
if ((save.length | 0) == 0x8000) {
|
||||
this.saves = save;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSRAMChip.prototype.read = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((address | 0) < 0x8000 || (this.TILTChipUnlocked | 0) != 3) {
|
||||
data = this.saves[address & 0x7FFF] | 0;
|
||||
}
|
||||
else {
|
||||
switch (address | 0) {
|
||||
case 0x8200:
|
||||
data = this.TILTChip.readXLow() | 0;
|
||||
break;
|
||||
case 0x8300:
|
||||
data = this.TILTChip.readXHigh() | 0;
|
||||
break;
|
||||
case 0x8400:
|
||||
data = this.TILTChip.readYLow() | 0;
|
||||
break;
|
||||
case 0x8500:
|
||||
data = this.TILTChip.readYHigh() | 0;
|
||||
break;
|
||||
default:
|
||||
data = this.saves[address & 0x7FFF] | 0;
|
||||
}
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceSRAMChip.prototype.write = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((address | 0) < 0x8000 || (this.TILTChipUnlocked | 0) >= 4) {
|
||||
//Normal SRAM write:
|
||||
this.saves[address & 0x7FFF] = data | 0;
|
||||
}
|
||||
else {
|
||||
switch (address | 0) {
|
||||
case 0x8000:
|
||||
if ((data | 0) == 0x55) { //Magic Combo.
|
||||
this.TILTChipUnlocked |= 0x1; //Tilt unlock stage 1.
|
||||
}
|
||||
else {
|
||||
this.TILTChipUnlocked |= 0x4; //Definitely not using a tilt sensor.
|
||||
}
|
||||
break;
|
||||
case 0x8100:
|
||||
if ((data | 0) == 0xAA) { //Magic Combo.
|
||||
this.TILTChipUnlocked |= 0x2; //Tilt unlock stage 2.
|
||||
}
|
||||
else {
|
||||
this.TILTChipUnlocked |= 0x4; //Definitely not using a tilt sensor.
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//Check for mirroring while not tilt chip:
|
||||
if ((this.TILTChipUnlocked | 0) == 0) {
|
||||
this.saves[address & 0x7FFF] = data | 0;
|
||||
this.TILTChipUnlocked |= 0x4; //Definitely not using a tilt sensor.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
158
public/gfiles/gba/IodineGBA/core/cartridge/SaveDeterminer.js
Normal file
158
public/gfiles/gba/IodineGBA/core/cartridge/SaveDeterminer.js
Normal file
|
@ -0,0 +1,158 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceSaveDeterminer(saveCore) {
|
||||
this.saves = null;
|
||||
this.saveCore = saveCore;
|
||||
this.possible = 0x7;
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.flags = {
|
||||
SRAM: 1,
|
||||
FLASH: 2,
|
||||
EEPROM: 4
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.initialize = function () {
|
||||
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.load = function (save) {
|
||||
this.saves = save;
|
||||
var length = save.length | 0;
|
||||
switch (length | 0) {
|
||||
case 0x200:
|
||||
case 0x2000:
|
||||
this.possible = this.flags.EEPROM | 0;
|
||||
break;
|
||||
case 0x8000:
|
||||
this.possible = this.flags.SRAM | 0;
|
||||
break;
|
||||
case 0x10000:
|
||||
case 0x20000:
|
||||
this.possible = this.flags.FLASH | 0;
|
||||
}
|
||||
this.checkDetermination();
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.checkDetermination = function () {
|
||||
switch (this.possible) {
|
||||
case 0x1:
|
||||
this.saveCore.referenceSave(0x1);
|
||||
break;
|
||||
case 0x2:
|
||||
this.saveCore.referenceSave(0x2);
|
||||
break;
|
||||
case 0x4:
|
||||
this.saveCore.referenceSave(0x3);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.readSRAM = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
//Is not EEPROM:
|
||||
this.possible &= ~this.flags.EEPROM;
|
||||
if (this.saves != null) {
|
||||
if ((this.possible & this.flags.FLASH) == (this.flags.FLASH | 0) || (this.possible & this.flags.SRAM) == (this.flags.SRAM | 0)) {
|
||||
//Read is the same between SRAM and FLASH for the most part:
|
||||
data = this.saves[(address | 0) % (this.saves.length | 0)] | 0;
|
||||
}
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.writeGPIO8 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
//GPIO (TODO):
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.writeGPIO16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
//GPIO (TODO):
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.writeGPIO32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
//GPIO (TODO):
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.writeEEPROM16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
if ((this.possible & this.flags.EEPROM) == (this.flags.EEPROM | 0)) {
|
||||
//EEPROM:
|
||||
this.possible = this.flags.EEPROM | 0;
|
||||
this.checkDetermination();
|
||||
this.saveCore.writeEEPROM16(address | 0, data | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.readEEPROM8 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.possible & this.flags.EEPROM) == (this.flags.EEPROM | 0)) {
|
||||
//EEPROM:
|
||||
this.possible = this.flags.EEPROM | 0;
|
||||
this.checkDetermination();
|
||||
return this.saveCore.readEEPROM8(address | 0) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.readEEPROM16 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.possible & this.flags.EEPROM) == (this.flags.EEPROM | 0)) {
|
||||
//EEPROM:
|
||||
this.possible = this.flags.EEPROM | 0;
|
||||
this.checkDetermination();
|
||||
return this.saveCore.readEEPROM16(address | 0) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.readEEPROM32 = function (address) {
|
||||
address = address | 0;
|
||||
var data = 0;
|
||||
if ((this.possible & this.flags.EEPROM) == (this.flags.EEPROM | 0)) {
|
||||
//EEPROM:
|
||||
this.possible = this.flags.EEPROM | 0;
|
||||
this.checkDetermination();
|
||||
return this.saveCore.readEEPROM32(address | 0) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceSaveDeterminer.prototype.writeSRAM = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
//Is not EEPROM:
|
||||
this.possible &= ~this.flags.EEPROM;
|
||||
if ((this.possible & this.flags.FLASH) == (this.flags.FLASH | 0)) {
|
||||
if ((this.possible & this.flags.SRAM) == (this.flags.SRAM | 0)) {
|
||||
if ((address | 0) == 0x5555) {
|
||||
if ((data | 0) == 0xAA) {
|
||||
//FLASH
|
||||
this.possible = this.flags.FLASH | 0;
|
||||
}
|
||||
else {
|
||||
//SRAM
|
||||
this.possible = this.flags.SRAM | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((address | 0) == 0x5555) {
|
||||
if ((data | 0) == 0xAA) {
|
||||
//FLASH
|
||||
this.possible = this.flags.FLASH | 0;
|
||||
}
|
||||
else {
|
||||
//Is not Flash:
|
||||
this.possible &= ~this.flags.FLASH;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((this.possible & this.flags.SRAM) == (this.flags.SRAM | 0)) {
|
||||
//SRAM
|
||||
this.possible = this.flags.SRAM | 0;
|
||||
}
|
||||
this.checkDetermination();
|
||||
this.saveCore.writeSRAMIfDefined(address | 0, data | 0);
|
||||
}
|
392
public/gfiles/gba/IodineGBA/core/graphics/AffineBG.js
Normal file
392
public/gfiles/gba/IodineGBA/core/graphics/AffineBG.js
Normal file
|
@ -0,0 +1,392 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceAffineBGRenderer(gfx, BGLayer) {
|
||||
BGLayer = BGLayer | 0;
|
||||
this.gfx = gfx;
|
||||
this.BGLayer = BGLayer | 0;
|
||||
this.offset = ((this.BGLayer << 8) + 0x100) | 0;
|
||||
}
|
||||
if (__VIEWS_SUPPORTED__) {
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.initialize = function () {
|
||||
this.bg2MatrixRenderer = this.gfx.bg2MatrixRenderer;
|
||||
this.bg3MatrixRenderer = this.gfx.bg3MatrixRenderer;
|
||||
this.bg2FrameBufferRenderer = this.gfx.bg2FrameBufferRenderer;
|
||||
this.scratchBuffer = getInt32ViewCustom(this.gfx.buffer, this.offset | 0, ((this.offset | 0) + 240) | 0);
|
||||
this.BGdx = 0x100;
|
||||
this.BGdmx = 0;
|
||||
this.BGdy = 0;
|
||||
this.BGdmy = 0x100;
|
||||
this.BGReferenceX = 0;
|
||||
this.BGReferenceY = 0;
|
||||
this.pb = 0;
|
||||
this.pd = 0;
|
||||
this.doMosaic = 0;
|
||||
this.priorityPreprocess(0);
|
||||
this.offsetReferenceCounters();
|
||||
}
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.renderScanLine2M = function (line) {
|
||||
line = line | 0;
|
||||
var x = this.pb | 0;
|
||||
var y = this.pd | 0;
|
||||
if ((this.doMosaic | 0) != 0) {
|
||||
//Correct line number for mosaic:
|
||||
var mosaicY = this.gfx.mosaicRenderer.getMosaicYOffset(line | 0) | 0;
|
||||
x = ((x | 0) - Math.imul(this.BGdmx | 0, mosaicY | 0)) | 0;
|
||||
y = ((y | 0) - Math.imul(this.BGdmy | 0, mosaicY | 0)) | 0;
|
||||
}
|
||||
for (var position = 0; (position | 0) < 240; position = ((position | 0) + 1) | 0, x = ((x | 0) + (this.BGdx | 0)) | 0, y = ((y | 0) + (this.BGdy | 0)) | 0) {
|
||||
//Fetch pixel:
|
||||
this.scratchBuffer[position | 0] = this.priorityFlag | this.bg2MatrixRenderer.fetchPixel(x >> 8, y >> 8);
|
||||
}
|
||||
if ((this.doMosaic | 0) != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.renderScanLine3M = function (line) {
|
||||
line = line | 0;
|
||||
var x = this.pb | 0;
|
||||
var y = this.pd | 0;
|
||||
if ((this.doMosaic | 0) != 0) {
|
||||
//Correct line number for mosaic:
|
||||
var mosaicY = this.gfx.mosaicRenderer.getMosaicYOffset(line | 0) | 0;
|
||||
x = ((x | 0) - Math.imul(this.BGdmx | 0, mosaicY | 0)) | 0;
|
||||
y = ((y | 0) - Math.imul(this.BGdmy | 0, mosaicY | 0)) | 0;
|
||||
}
|
||||
for (var position = 0; (position | 0) < 240; position = ((position | 0) + 1) | 0, x = ((x | 0) + (this.BGdx | 0)) | 0, y = ((y | 0) + (this.BGdy | 0)) | 0) {
|
||||
//Fetch pixel:
|
||||
this.scratchBuffer[position | 0] = this.priorityFlag | this.bg3MatrixRenderer.fetchPixel(x >> 8, y >> 8);
|
||||
}
|
||||
if ((this.doMosaic | 0) != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.renderScanLine2F = function (line) {
|
||||
line = line | 0;
|
||||
var x = this.pb | 0;
|
||||
var y = this.pd | 0;
|
||||
if ((this.doMosaic | 0) != 0) {
|
||||
//Correct line number for mosaic:
|
||||
var mosaicY = this.gfx.mosaicRenderer.getMosaicYOffset(line | 0) | 0;
|
||||
x = ((x | 0) - Math.imul(this.BGdmx | 0, mosaicY | 0)) | 0;
|
||||
y = ((y | 0) - Math.imul(this.BGdmy | 0, mosaicY | 0)) | 0;
|
||||
}
|
||||
for (var position = 0; (position | 0) < 240; position = ((position | 0) + 1) | 0, x = ((x | 0) + (this.BGdx | 0)) | 0, y = ((y | 0) + (this.BGdy | 0)) | 0) {
|
||||
//Fetch pixel:
|
||||
this.scratchBuffer[position | 0] = this.priorityFlag | this.bg2FrameBufferRenderer.fetchPixel(x >> 8, y >> 8);
|
||||
}
|
||||
if ((this.doMosaic | 0) != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.offsetReferenceCounters = function () {
|
||||
var end = this.gfx.lastUnrenderedLine | 0;
|
||||
this.pb = Math.imul(((this.pb | 0) + (this.BGdmx | 0)) | 0, end | 0) | 0;
|
||||
this.pd = Math.imul(((this.pd | 0) + (this.BGdmy | 0)) | 0, end | 0) | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.renderScanLine2M = function (line) {
|
||||
var x = this.pb;
|
||||
var y = this.pd;
|
||||
if (this.doMosaic != 0) {
|
||||
//Correct line number for mosaic:
|
||||
var mosaicY = this.gfx.mosaicRenderer.getMosaicYOffset(line);
|
||||
x -= this.BGdmx * mosaicY;
|
||||
y -= this.BGdmy * mosaicY;
|
||||
}
|
||||
for (var position = 0; position < 240; ++position, x += this.BGdx, y += this.BGdy) {
|
||||
//Fetch pixel:
|
||||
this.scratchBuffer[position] = this.priorityFlag | this.bg2MatrixRenderer.fetchPixel(x >> 8, y >> 8);
|
||||
}
|
||||
if (this.doMosaic != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.renderScanLine3M = function (line) {
|
||||
var x = this.pb;
|
||||
var y = this.pd;
|
||||
if (this.doMosaic != 0) {
|
||||
//Correct line number for mosaic:
|
||||
var mosaicY = this.gfx.mosaicRenderer.getMosaicYOffset(line);
|
||||
x -= this.BGdmx * mosaicY;
|
||||
y -= this.BGdmy * mosaicY;
|
||||
}
|
||||
for (var position = 0; position < 240; ++position, x += this.BGdx, y += this.BGdy) {
|
||||
//Fetch pixel:
|
||||
this.scratchBuffer[position] = this.priorityFlag | this.bg3MatrixRenderer.fetchPixel(x >> 8, y >> 8);
|
||||
}
|
||||
if (this.doMosaic != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.renderScanLine2F = function (line) {
|
||||
var x = this.pb;
|
||||
var y = this.pd;
|
||||
if (this.doMosaic != 0) {
|
||||
//Correct line number for mosaic:
|
||||
var mosaicY = this.gfx.mosaicRenderer.getMosaicYOffset(line);
|
||||
x -= this.BGdmx * mosaicY;
|
||||
y -= this.BGdmy * mosaicY;
|
||||
}
|
||||
for (var position = 0; position < 240; ++position, x += this.BGdx, y += this.BGdy) {
|
||||
//Fetch pixel:
|
||||
this.scratchBuffer[position] = this.priorityFlag | this.bg2FrameBufferRenderer.fetchPixel(x >> 8, y >> 8);
|
||||
}
|
||||
if (this.doMosaic != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.offsetReferenceCounters = function () {
|
||||
var end = this.gfx.lastUnrenderedLine | 0;
|
||||
this.pb = (((this.pb | 0) + (this.BGdmx | 0)) * (end | 0)) | 0;
|
||||
this.pd = (((this.pd | 0) + (this.BGdmy | 0)) * (end | 0)) | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.initialize = function () {
|
||||
this.bg2MatrixRenderer = this.gfx.bg2MatrixRenderer;
|
||||
this.bg3MatrixRenderer = this.gfx.bg3MatrixRenderer;
|
||||
this.bg2FrameBufferRenderer = this.gfx.bg2FrameBufferRenderer;
|
||||
this.scratchBuffer = this.gfx.buffer;
|
||||
this.BGdx = 0x100;
|
||||
this.BGdmx = 0;
|
||||
this.BGdy = 0;
|
||||
this.BGdmy = 0x100;
|
||||
this.BGReferenceX = 0;
|
||||
this.BGReferenceY = 0;
|
||||
this.pb = 0;
|
||||
this.pd = 0;
|
||||
this.doMosaic = 0;
|
||||
this.priorityPreprocess(0);
|
||||
this.offsetReferenceCounters();
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.renderScanLine2M = function (line) {
|
||||
var x = this.pb;
|
||||
var y = this.pd;
|
||||
if (this.doMosaic != 0) {
|
||||
//Correct line number for mosaic:
|
||||
var mosaicY = this.gfx.mosaicRenderer.getMosaicYOffset(line);
|
||||
x -= this.BGdmx * mosaicY;
|
||||
y -= this.BGdmy * mosaicY;
|
||||
}
|
||||
for (var position = 0; position < 240; ++position, x += this.BGdx, y += this.BGdy) {
|
||||
//Fetch pixel:
|
||||
this.scratchBuffer[this.offset + position] = this.priorityFlag | this.bg2MatrixRenderer.fetchPixel(x >> 8, y >> 8);
|
||||
}
|
||||
if (this.doMosaic != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.renderScanLine3M = function (line) {
|
||||
var x = this.pb;
|
||||
var y = this.pd;
|
||||
if (this.doMosaic != 0) {
|
||||
//Correct line number for mosaic:
|
||||
var mosaicY = this.gfx.mosaicRenderer.getMosaicYOffset(line);
|
||||
x -= this.BGdmx * mosaicY;
|
||||
y -= this.BGdmy * mosaicY;
|
||||
}
|
||||
for (var position = 0; position < 240; ++position, x += this.BGdx, y += this.BGdy) {
|
||||
//Fetch pixel:
|
||||
this.scratchBuffer[this.offset + position] = this.priorityFlag | this.bg3MatrixRenderer.fetchPixel(x >> 8, y >> 8);
|
||||
}
|
||||
if (this.doMosaic != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.renderScanLine2F = function (line) {
|
||||
var x = this.pb;
|
||||
var y = this.pd;
|
||||
if (this.doMosaic != 0) {
|
||||
//Correct line number for mosaic:
|
||||
var mosaicY = this.gfx.mosaicRenderer.getMosaicYOffset(line);
|
||||
x -= this.BGdmx * mosaicY;
|
||||
y -= this.BGdmy * mosaicY;
|
||||
}
|
||||
for (var position = 0; position < 240; ++position, x += this.BGdx, y += this.BGdy) {
|
||||
//Fetch pixel:
|
||||
this.scratchBuffer[this.offset + position] = this.priorityFlag | this.bg2FrameBufferRenderer.fetchPixel(x >> 8, y >> 8);
|
||||
}
|
||||
if (this.doMosaic != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.offsetReferenceCounters = function () {
|
||||
var end = this.gfx.lastUnrenderedLine | 0;
|
||||
this.pb = (((this.pb | 0) + (this.BGdmx | 0)) * (end | 0)) | 0;
|
||||
this.pd = (((this.pd | 0) + (this.BGdmy | 0)) * (end | 0)) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.incrementReferenceCounters = function () {
|
||||
this.pb = ((this.pb | 0) + (this.BGdmx | 0)) | 0;
|
||||
this.pd = ((this.pd | 0) + (this.BGdmy | 0)) | 0;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.resetReferenceCounters = function () {
|
||||
this.pb = this.BGReferenceX | 0;
|
||||
this.pd = this.BGReferenceY | 0;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.setMosaicEnable = function (doMosaic) {
|
||||
doMosaic = doMosaic | 0;
|
||||
this.doMosaic = doMosaic | 0;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.priorityPreprocess = function (BGPriority) {
|
||||
BGPriority = BGPriority | 0;
|
||||
this.priorityFlag = (BGPriority << 23) | (1 << (this.BGLayer | 0x10));
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPA8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdx = (this.BGdx & 0xFFFFFF00) | data;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPA8_1 = function (data) {
|
||||
data = data | 0;
|
||||
data = (data << 24) >> 16;
|
||||
this.BGdx = data | (this.BGdx & 0xFF);
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPA16 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdx = (data << 16) >> 16;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPB8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdmx = (this.BGdmx & 0xFFFFFF00) | data;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPB8_1 = function (data) {
|
||||
data = data | 0;
|
||||
data = (data << 24) >> 16;
|
||||
this.BGdmx = data | (this.BGdmx & 0xFF);
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPB16 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdmx = (data << 16) >> 16;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPAB32 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdx = (data << 16) >> 16;
|
||||
this.BGdmx = data >> 16;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPC8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdy = (this.BGdy & 0xFFFFFF00) | data;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPC8_1 = function (data) {
|
||||
data = data | 0;
|
||||
data = (data << 24) >> 16;
|
||||
this.BGdy = data | (this.BGdy & 0xFF);
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPC16 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdy = (data << 16) >> 16;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPD8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdmy = (this.BGdmy & 0xFFFFFF00) | data;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPD8_1 = function (data) {
|
||||
data = data | 0;
|
||||
data = (data << 24) >> 16;
|
||||
this.BGdmy = data | (this.BGdmy & 0xFF);
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPD16 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdmy = (data << 16) >> 16;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGPCD32 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGdy = (data << 16) >> 16;
|
||||
this.BGdmy = data >> 16;
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGX8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceX = (this.BGReferenceX & 0xFFFFFF00) | data;
|
||||
//Writing to the x reference doesn't reset the counters during draw!
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGX8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceX = (data << 8) | (this.BGReferenceX & 0xFFFF00FF);
|
||||
//Writing to the x reference doesn't reset the counters during draw!
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGX8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceX = (data << 16) | (this.BGReferenceX & 0xFF00FFFF);
|
||||
//Writing to the x reference doesn't reset the counters during draw!
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGX8_3 = function (data) {
|
||||
data = data | 0;
|
||||
data = (data << 28) >> 4;
|
||||
this.BGReferenceX = data | (this.BGReferenceX & 0xFFFFFF);
|
||||
//Writing to the x reference doesn't reset the counters during draw!
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGX16_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceX = (this.BGReferenceX & 0xFFFF0000) | data;
|
||||
//Writing to the x reference doesn't reset the counters during draw!
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGX16_1 = function (data) {
|
||||
data = data | 0;
|
||||
data = (data << 20) >> 4;
|
||||
this.BGReferenceX = (this.BGReferenceX & 0xFFFF) | data;
|
||||
//Writing to the x reference doesn't reset the counters during draw!
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGX32 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceX = (data << 4) >> 4;
|
||||
//Writing to the x reference doesn't reset the counters during draw!
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGY8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceY = (this.BGReferenceY & 0xFFFFFF00) | data;
|
||||
this.resetReferenceCounters();
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGY8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceY = (data << 8) | (this.BGReferenceY & 0xFFFF00FF);
|
||||
this.resetReferenceCounters();
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGY8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceY = (data << 16) | (this.BGReferenceY & 0xFF00FFFF);
|
||||
this.resetReferenceCounters();
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGY8_3 = function (data) {
|
||||
data = data | 0;
|
||||
data = (data << 28) >> 4;
|
||||
this.BGReferenceY = data | (this.BGReferenceY & 0xFFFFFF);
|
||||
this.resetReferenceCounters();
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGY16_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceY = (this.BGReferenceY & 0xFFFF0000) | data;
|
||||
this.resetReferenceCounters();
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGY16_1 = function (data) {
|
||||
data = data | 0;
|
||||
data = (data << 20) >> 4;
|
||||
this.BGReferenceY = (this.BGReferenceY & 0xFFFF) | data;
|
||||
this.resetReferenceCounters();
|
||||
}
|
||||
GameBoyAdvanceAffineBGRenderer.prototype.writeBGY32 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGReferenceY = (data << 4) >> 4;
|
||||
this.resetReferenceCounters();
|
||||
}
|
162
public/gfiles/gba/IodineGBA/core/graphics/BG2FrameBuffer.js
Normal file
162
public/gfiles/gba/IodineGBA/core/graphics/BG2FrameBuffer.js
Normal file
|
@ -0,0 +1,162 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceBG2FrameBufferRenderer(gfx) {
|
||||
this.gfx = gfx;
|
||||
}
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.initialize = function () {
|
||||
this.palette = this.gfx.palette256;
|
||||
this.VRAM = this.gfx.VRAM;
|
||||
this.VRAM16 = this.gfx.VRAM16;
|
||||
this.fetchPixel = this.fetchMode3Pixel;
|
||||
this.frameSelect = 0;
|
||||
}
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.selectMode = function (mode) {
|
||||
mode = mode | 0;
|
||||
switch (mode | 0) {
|
||||
case 3:
|
||||
this.fetchPixel = this.fetchMode3Pixel;
|
||||
break;
|
||||
case 4:
|
||||
this.fetchPixel = this.fetchMode4Pixel;
|
||||
break;
|
||||
case 5:
|
||||
this.fetchPixel = this.fetchMode5Pixel;
|
||||
}
|
||||
}
|
||||
if (__LITTLE_ENDIAN__) {
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode3Pixel = function (x, y) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 240 && (y >>> 0) < 160) {
|
||||
var address = (Math.imul(y | 0, 240) + (x | 0)) | 0;
|
||||
return this.VRAM16[address & 0xFFFF] & 0x7FFF;
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode5Pixel = function (x, y) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 160 && (y >>> 0) < 128) {
|
||||
var address = ((this.frameSelect | 0) + Math.imul(y | 0, 160) + (x | 0)) | 0;
|
||||
return this.VRAM16[address & 0xFFFF] & 0x7FFF;
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode3Pixel = function (x, y) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 240 && (y >>> 0) < 160) {
|
||||
var address = (((y * 240) | 0) + (x | 0)) | 0;
|
||||
return this.VRAM16[address & 0xFFFF] & 0x7FFF;
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode5Pixel = function (x, y) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 160 && (y >>> 0) < 128) {
|
||||
var address = ((this.frameSelect | 0) + ((y * 160) | 0) + (x | 0)) | 0;
|
||||
return this.VRAM16[address & 0xFFFF] & 0x7FFF;
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode3Pixel = function (x, y) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 240 && (y >>> 0) < 160) {
|
||||
var address = (Math.imul(y | 0, 240) + (x | 0)) << 1;
|
||||
return ((this.VRAM[address | 1] << 8) | this.VRAM[address | 0]) & 0x7FFF;
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode5Pixel = function (x, y) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 160 && (y >>> 0) < 128) {
|
||||
var address = ((this.frameSelect | 0) + ((Math.imul(y | 0, 160) + (x | 0)) << 1)) | 0;
|
||||
return ((this.VRAM[address | 1] << 8) | this.VRAM[address | 0]) & 0x7FFF;
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode3Pixel = function (x, y) {
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 240 && (y >>> 0) < 160) {
|
||||
var address = ((y * 240) + x) << 1;
|
||||
return ((this.VRAM[address | 1] << 8) | this.VRAM[address]) & 0x7FFF;
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode5Pixel = function (x, y) {
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 160 && (y >>> 0) < 128) {
|
||||
var address = this.frameSelect + (((y * 160) + x) << 1);
|
||||
return ((this.VRAM[address | 1] << 8) | this.VRAM[address]) & 0x7FFF;
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode4Pixel = function (x, y) {
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 240 && (y >>> 0) < 160) {
|
||||
var address = ((this.frameSelect | 0) + (Math.imul(y | 0, 240) | 0) + (x | 0)) | 0;
|
||||
return this.palette[this.VRAM[address | 0] & 0xFF] | 0;
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.fetchMode4Pixel = function (x, y) {
|
||||
//Output pixel:
|
||||
if ((x >>> 0) < 240 && (y >>> 0) < 160) {
|
||||
return this.palette[this.VRAM[this.frameSelect + (y * 240) + x]];
|
||||
}
|
||||
//Out of range, output transparency:
|
||||
return 0x3800000;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBG2FrameBufferRenderer.prototype.writeFrameSelect = function (frameSelect) {
|
||||
frameSelect = frameSelect >> 31;
|
||||
this.frameSelect = frameSelect & 0xA000;
|
||||
}
|
99
public/gfiles/gba/IodineGBA/core/graphics/BGMatrix.js
Normal file
99
public/gfiles/gba/IodineGBA/core/graphics/BGMatrix.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceBGMatrixRenderer(gfx) {
|
||||
this.gfx = gfx;
|
||||
}
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.initialize = function () {
|
||||
this.VRAM = this.gfx.VRAM;
|
||||
this.palette = this.gfx.palette256;
|
||||
this.screenSizePreprocess(0);
|
||||
this.screenBaseBlockPreprocess(0);
|
||||
this.characterBaseBlockPreprocess(0);
|
||||
this.displayOverflowProcess(0);
|
||||
}
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.fetchTile = function (x, y) {
|
||||
//Compute address for tile VRAM to address:
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
var tileNumber = ((x | 0) + Math.imul(y | 0, this.mapSize | 0)) | 0;
|
||||
return this.VRAM[((tileNumber | 0) + (this.BGScreenBaseBlock | 0)) & 0xFFFF] | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.fetchTile = function (x, y) {
|
||||
//Compute address for tile VRAM to address:
|
||||
var tileNumber = x + (y * this.mapSize);
|
||||
return this.VRAM[(tileNumber + this.BGScreenBaseBlock) & 0xFFFF];
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.computeScreenAddress = function (x, y) {
|
||||
//Compute address for character VRAM to address:
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
var address = this.fetchTile(x >> 3, y >> 3) << 6;
|
||||
address = ((address | 0) + (this.BGCharacterBaseBlock | 0)) | 0;
|
||||
address = ((address | 0) + ((y & 0x7) << 3)) | 0;
|
||||
address = ((address | 0) + (x & 0x7)) | 0;
|
||||
return address | 0;
|
||||
}
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.fetchPixelOverflow = function (x, y) {
|
||||
//Fetch the pixel:
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
//Output pixel:
|
||||
var address = this.computeScreenAddress(x & this.mapSizeComparer, y & this.mapSizeComparer) | 0;
|
||||
return this.palette[this.VRAM[address & 0xFFFF] & 0xFF] | 0;
|
||||
}
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.fetchPixelNoOverflow = function (x, y) {
|
||||
//Fetch the pixel:
|
||||
x = x | 0;
|
||||
y = y | 0;
|
||||
//Output pixel:
|
||||
if ((x | 0) != (x & this.mapSizeComparer) || (y | 0) != (y & this.mapSizeComparer)) {
|
||||
//Overflow Handling:
|
||||
//Out of bounds with no overflow allowed:
|
||||
return 0x3800000;
|
||||
}
|
||||
var address = this.computeScreenAddress(x | 0, y | 0) | 0;
|
||||
return this.palette[this.VRAM[address & 0xFFFF] & 0xFF] | 0;
|
||||
}
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.screenBaseBlockPreprocess = function (BGScreenBaseBlock) {
|
||||
BGScreenBaseBlock = BGScreenBaseBlock | 0;
|
||||
this.BGScreenBaseBlock = BGScreenBaseBlock << 11;
|
||||
}
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.characterBaseBlockPreprocess = function (BGCharacterBaseBlock) {
|
||||
BGCharacterBaseBlock = BGCharacterBaseBlock | 0;
|
||||
this.BGCharacterBaseBlock = BGCharacterBaseBlock << 14;
|
||||
}
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.screenSizePreprocess = function (BGScreenSize) {
|
||||
BGScreenSize = BGScreenSize | 0;
|
||||
this.mapSize = 0x10 << (BGScreenSize | 0);
|
||||
this.mapSizeComparer = ((this.mapSize << 3) - 1) | 0;
|
||||
}
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.displayOverflowPreprocess = function (doOverflow) {
|
||||
doOverflow = doOverflow | 0;
|
||||
if ((doOverflow | 0) != (this.BGDisplayOverflow | 0)) {
|
||||
this.displayOverflowProcess(doOverflow | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGMatrixRenderer.prototype.displayOverflowProcess = function (doOverflow) {
|
||||
doOverflow = doOverflow | 0;
|
||||
this.BGDisplayOverflow = doOverflow | 0;
|
||||
if ((doOverflow | 0) != 0) {
|
||||
this.fetchPixel = this.fetchPixelOverflow;
|
||||
}
|
||||
else {
|
||||
this.fetchPixel = this.fetchPixelNoOverflow;
|
||||
}
|
||||
}
|
577
public/gfiles/gba/IodineGBA/core/graphics/BGTEXT.js
Normal file
577
public/gfiles/gba/IodineGBA/core/graphics/BGTEXT.js
Normal file
|
@ -0,0 +1,577 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceBGTEXTRenderer(gfx, BGLayer) {
|
||||
BGLayer = BGLayer | 0;
|
||||
this.gfx = gfx;
|
||||
this.BGLayer = BGLayer | 0;
|
||||
}
|
||||
if (__VIEWS_SUPPORTED__) {
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.initialize = function () {
|
||||
this.VRAM = this.gfx.VRAM;
|
||||
this.VRAM16 = this.gfx.VRAM16;
|
||||
this.VRAM32 = this.gfx.VRAM32;
|
||||
this.palette16 = this.gfx.palette16;
|
||||
this.palette256 = this.gfx.palette256;
|
||||
this.offset = ((this.BGLayer << 8) + 0x100) | 0;
|
||||
this.scratchBuffer = getInt32ViewCustom(this.gfx.buffer, this.offset | 0, ((this.offset | 0) + 248) | 0);
|
||||
this.tileFetched = getInt32ViewCustom(this.gfx.buffer, ((this.offset | 0) + 0xF8) | 0, ((this.offset | 0) + 0x100) | 0);
|
||||
this.BGXCoord = 0;
|
||||
this.BGYCoord = 0;
|
||||
this.do256 = 0;
|
||||
this.doMosaic = 0;
|
||||
this.screenSizePreprocess(0);
|
||||
this.priorityPreprocess(0);
|
||||
this.screenBaseBlockPreprocess(0);
|
||||
this.characterBaseBlockPreprocess(0);
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.renderWholeTiles8BIT = function (xTileStart, yTileStart, yTileOffset) {
|
||||
xTileStart = xTileStart | 0;
|
||||
yTileStart = yTileStart | 0;
|
||||
yTileOffset = yTileOffset | 0;
|
||||
//Process full 8 pixels at a time:
|
||||
for (var position = (8 - (this.BGXCoord & 0x7)) | 0; (position | 0) < 240; position = ((position | 0) + 8) | 0) {
|
||||
//Fetch tile attributes:
|
||||
//Get 8 pixels of data:
|
||||
this.process8BitVRAM(this.fetchTile(yTileStart | 0, xTileStart | 0) | 0, yTileOffset | 0);
|
||||
//Copy the buffered tile to line:
|
||||
this.scratchBuffer[position | 0] = this.tileFetched[0] | 0;
|
||||
this.scratchBuffer[((position | 0) + 1) | 0] = this.tileFetched[1] | 0;
|
||||
this.scratchBuffer[((position | 0) + 2) | 0] = this.tileFetched[2] | 0;
|
||||
this.scratchBuffer[((position | 0) + 3) | 0] = this.tileFetched[3] | 0;
|
||||
this.scratchBuffer[((position | 0) + 4) | 0] = this.tileFetched[4] | 0;
|
||||
this.scratchBuffer[((position | 0) + 5) | 0] = this.tileFetched[5] | 0;
|
||||
this.scratchBuffer[((position | 0) + 6) | 0] = this.tileFetched[6] | 0;
|
||||
this.scratchBuffer[((position | 0) + 7) | 0] = this.tileFetched[7] | 0;
|
||||
//Increment a tile counter:
|
||||
xTileStart = ((xTileStart | 0) + 1) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.renderWholeTiles4BIT = function (xTileStart, yTileStart, yTileOffset) {
|
||||
xTileStart = xTileStart | 0;
|
||||
yTileStart = yTileStart | 0;
|
||||
yTileOffset = yTileOffset | 0;
|
||||
//Process full 8 pixels at a time:
|
||||
for (var position = (8 - (this.BGXCoord & 0x7)) | 0; (position | 0) < 240; position = ((position | 0) + 8) | 0) {
|
||||
//Fetch tile attributes:
|
||||
//Get 8 pixels of data:
|
||||
this.process4BitVRAM(this.fetchTile(yTileStart | 0, xTileStart | 0) | 0, yTileOffset | 0);
|
||||
//Copy the buffered tile to line:
|
||||
this.scratchBuffer[position | 0] = this.tileFetched[0] | 0;
|
||||
this.scratchBuffer[((position | 0) + 1) | 0] = this.tileFetched[1] | 0;
|
||||
this.scratchBuffer[((position | 0) + 2) | 0] = this.tileFetched[2] | 0;
|
||||
this.scratchBuffer[((position | 0) + 3) | 0] = this.tileFetched[3] | 0;
|
||||
this.scratchBuffer[((position | 0) + 4) | 0] = this.tileFetched[4] | 0;
|
||||
this.scratchBuffer[((position | 0) + 5) | 0] = this.tileFetched[5] | 0;
|
||||
this.scratchBuffer[((position | 0) + 6) | 0] = this.tileFetched[6] | 0;
|
||||
this.scratchBuffer[((position | 0) + 7) | 0] = this.tileFetched[7] | 0;
|
||||
//Increment a tile counter:
|
||||
xTileStart = ((xTileStart | 0) + 1) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.fetchVRAMStart = function () {
|
||||
//Handle the the first tile of the scan-line specially:
|
||||
var pixelPipelinePosition = this.BGXCoord & 0x7;
|
||||
switch (pixelPipelinePosition | 0) {
|
||||
case 0:
|
||||
this.scratchBuffer[0] = this.tileFetched[0] | 0;
|
||||
case 1:
|
||||
this.scratchBuffer[(1 - (pixelPipelinePosition | 0)) | 0] = this.tileFetched[1] | 0;
|
||||
case 2:
|
||||
this.scratchBuffer[(2 - (pixelPipelinePosition | 0)) | 0] = this.tileFetched[2] | 0;
|
||||
case 3:
|
||||
this.scratchBuffer[(3 - (pixelPipelinePosition | 0)) | 0] = this.tileFetched[3] | 0;
|
||||
case 4:
|
||||
this.scratchBuffer[(4 - (pixelPipelinePosition | 0)) | 0] = this.tileFetched[4] | 0;
|
||||
case 5:
|
||||
this.scratchBuffer[(5 - (pixelPipelinePosition | 0)) | 0] = this.tileFetched[5] | 0;
|
||||
case 6:
|
||||
this.scratchBuffer[(6 - (pixelPipelinePosition | 0)) | 0] = this.tileFetched[6] | 0;
|
||||
default:
|
||||
this.scratchBuffer[(7 - (pixelPipelinePosition | 0)) | 0] = this.tileFetched[7] | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.initialize = function () {
|
||||
this.VRAM = this.gfx.VRAM;
|
||||
this.VRAM16 = this.gfx.VRAM16;
|
||||
this.VRAM32 = this.gfx.VRAM32;
|
||||
this.palette16 = this.gfx.palette16;
|
||||
this.palette256 = this.gfx.palette256;
|
||||
this.offset = (this.BGLayer << 8) + 0x100;
|
||||
this.offsetEnd = this.offset + 240;
|
||||
this.scratchBuffer = this.gfx.buffer;
|
||||
this.tileFetched = getInt32Array(8);
|
||||
this.BGXCoord = 0;
|
||||
this.BGYCoord = 0;
|
||||
this.do256 = 0;
|
||||
this.doMosaic = 0;
|
||||
this.screenSizePreprocess(0);
|
||||
this.priorityPreprocess(0);
|
||||
this.screenBaseBlockPreprocess(0);
|
||||
this.characterBaseBlockPreprocess(0);
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.renderWholeTiles8BIT = function (xTileStart, yTileStart, yTileOffset) {
|
||||
//Process full 8 pixels at a time:
|
||||
for (var position = 8 - (this.BGXCoord & 0x7) + this.offset; position < this.offsetEnd;) {
|
||||
//Fetch tile attributes:
|
||||
//Get 8 pixels of data:
|
||||
this.process8BitVRAM(this.fetchTile(yTileStart, xTileStart++), yTileOffset);
|
||||
//Copy the buffered tile to line:
|
||||
this.scratchBuffer[position++] = this.tileFetched[0];
|
||||
this.scratchBuffer[position++] = this.tileFetched[1];
|
||||
this.scratchBuffer[position++] = this.tileFetched[2];
|
||||
this.scratchBuffer[position++] = this.tileFetched[3];
|
||||
this.scratchBuffer[position++] = this.tileFetched[4];
|
||||
this.scratchBuffer[position++] = this.tileFetched[5];
|
||||
this.scratchBuffer[position++] = this.tileFetched[6];
|
||||
this.scratchBuffer[position++] = this.tileFetched[7];
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.renderWholeTiles4BIT = function (xTileStart, yTileStart, yTileOffset) {
|
||||
//Process full 8 pixels at a time:
|
||||
for (var position = 8 - (this.BGXCoord & 0x7) + this.offset; position < this.offsetEnd;) {
|
||||
//Fetch tile attributes:
|
||||
//Get 8 pixels of data:
|
||||
this.process4BitVRAM(this.fetchTile(yTileStart, xTileStart++), yTileOffset);
|
||||
//Copy the buffered tile to line:
|
||||
this.scratchBuffer[position++] = this.tileFetched[0];
|
||||
this.scratchBuffer[position++] = this.tileFetched[1];
|
||||
this.scratchBuffer[position++] = this.tileFetched[2];
|
||||
this.scratchBuffer[position++] = this.tileFetched[3];
|
||||
this.scratchBuffer[position++] = this.tileFetched[4];
|
||||
this.scratchBuffer[position++] = this.tileFetched[5];
|
||||
this.scratchBuffer[position++] = this.tileFetched[6];
|
||||
this.scratchBuffer[position++] = this.tileFetched[7];
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.fetchVRAMStart = function () {
|
||||
//Handle the the first tile of the scan-line specially:
|
||||
var pixelPipelinePosition = this.BGXCoord & 0x7;
|
||||
var offset = pixelPipelinePosition - this.offset;
|
||||
switch (pixelPipelinePosition | 0) {
|
||||
case 0:
|
||||
this.scratchBuffer[offset] = this.tileFetched[0];
|
||||
case 1:
|
||||
this.scratchBuffer[1 - offset] = this.tileFetched[1];
|
||||
case 2:
|
||||
this.scratchBuffer[2 - offset] = this.tileFetched[2];
|
||||
case 3:
|
||||
this.scratchBuffer[3 - offset] = this.tileFetched[3];
|
||||
case 4:
|
||||
this.scratchBuffer[4 - offset] = this.tileFetched[4];
|
||||
case 5:
|
||||
this.scratchBuffer[5 - offset] = this.tileFetched[5];
|
||||
case 6:
|
||||
this.scratchBuffer[6 - offset] = this.tileFetched[6];
|
||||
default:
|
||||
this.scratchBuffer[7 - offset] = this.tileFetched[7];
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.renderScanLine = function (line) {
|
||||
line = line | 0;
|
||||
if ((this.doMosaic | 0) != 0) {
|
||||
//Correct line number for mosaic:
|
||||
line = ((line | 0) - (this.gfx.mosaicRenderer.getMosaicYOffset(line | 0) | 0)) | 0;
|
||||
}
|
||||
var yTileOffset = ((line | 0) + (this.BGYCoord | 0)) & 0x7;
|
||||
var yTileStart = ((line | 0) + (this.BGYCoord | 0)) >> 3;
|
||||
var xTileStart = this.BGXCoord >> 3;
|
||||
//Render the tiles:
|
||||
if ((this.do256 | 0) != 0) {
|
||||
//8-bit palette mode:
|
||||
this.render8BITLine(yTileStart | 0, xTileStart | 0, yTileOffset | 0);
|
||||
}
|
||||
else {
|
||||
//4-bit palette mode:
|
||||
this.render4BITLine(yTileStart | 0, xTileStart | 0, yTileOffset | 0);
|
||||
}
|
||||
if ((this.doMosaic | 0) != 0) {
|
||||
//Pixelize the line horizontally:
|
||||
this.gfx.mosaicRenderer.renderMosaicHorizontal(this.offset | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.render8BITLine = function (yTileStart, xTileStart, yTileOffset) {
|
||||
yTileStart = yTileStart | 0;
|
||||
xTileStart = xTileStart | 0;
|
||||
yTileOffset = yTileOffset | 0;
|
||||
//Fetch tile attributes:
|
||||
var chrData = this.fetchTile(yTileStart | 0, xTileStart | 0) | 0;
|
||||
xTileStart = ((xTileStart | 0) + 1) | 0;
|
||||
//Get 8 pixels of data:
|
||||
this.process8BitVRAM(chrData | 0, yTileOffset | 0);
|
||||
//Copy the buffered tile to line:
|
||||
this.fetchVRAMStart();
|
||||
//Render the rest of the tiles fast:
|
||||
this.renderWholeTiles8BIT(xTileStart | 0, yTileStart | 0, yTileOffset | 0);
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.render4BITLine = function (yTileStart, xTileStart, yTileOffset) {
|
||||
//Fetch tile attributes:
|
||||
var chrData = this.fetchTile(yTileStart | 0, xTileStart | 0) | 0;
|
||||
xTileStart = ((xTileStart | 0) + 1) | 0;
|
||||
//Get 8 pixels of data:
|
||||
this.process4BitVRAM(chrData | 0, yTileOffset | 0);
|
||||
//Copy the buffered tile to line:
|
||||
this.fetchVRAMStart();
|
||||
//Render the rest of the tiles fast:
|
||||
this.renderWholeTiles4BIT(xTileStart | 0, yTileStart | 0, yTileOffset | 0);
|
||||
}
|
||||
if (__LITTLE_ENDIAN__) {
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.fetchTile = function (yTileStart, xTileStart) {
|
||||
yTileStart = yTileStart | 0;
|
||||
xTileStart = xTileStart | 0;
|
||||
//Find the tile code to locate the tile block:
|
||||
var address = ((this.computeTileNumber(yTileStart | 0, xTileStart | 0) | 0) + (this.BGScreenBaseBlock | 0)) | 0;
|
||||
return this.VRAM16[address & 0x7FFF] | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.fetchTile = function (yTileStart, xTileStart) {
|
||||
//Find the tile code to locate the tile block:
|
||||
var address = ((this.computeTileNumber(yTileStart, xTileStart) + this.BGScreenBaseBlock) << 1) & 0xFFFF;
|
||||
return (this.VRAM[address | 1] << 8) | this.VRAM[address];
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.computeTileNumber = function (yTile, xTile) {
|
||||
//Return the true tile number:
|
||||
yTile = yTile | 0;
|
||||
xTile = xTile | 0;
|
||||
var tileNumber = xTile & 0x1F;
|
||||
switch (this.tileMode | 0) {
|
||||
//1x1
|
||||
case 0:
|
||||
tileNumber = tileNumber | ((yTile & 0x1F) << 5);
|
||||
break;
|
||||
//2x1
|
||||
case 1:
|
||||
tileNumber = tileNumber | (((xTile & 0x20) | (yTile & 0x1F)) << 5);
|
||||
break;
|
||||
//1x2
|
||||
case 2:
|
||||
tileNumber = tileNumber | ((yTile & 0x3F) << 5);
|
||||
break;
|
||||
//2x2
|
||||
default:
|
||||
tileNumber = tileNumber | (((xTile & 0x20) | (yTile & 0x1F)) << 5) | ((yTile & 0x20) << 6);
|
||||
}
|
||||
return tileNumber | 0;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.process4BitVRAM = function (chrData, yOffset) {
|
||||
//16 color tile mode:
|
||||
chrData = chrData | 0;
|
||||
yOffset = yOffset | 0;
|
||||
//Parse flip attributes, grab palette, and then output pixel:
|
||||
var address = (chrData & 0x3FF) << 3;
|
||||
address = ((address | 0) + (this.BGCharacterBaseBlock | 0)) | 0;
|
||||
if ((chrData & 0x800) == 0) {
|
||||
//No vertical flip:
|
||||
address = ((address | 0) + (yOffset | 0)) | 0;
|
||||
|
||||
}
|
||||
else {
|
||||
//Vertical flip:
|
||||
address = ((address | 0) + 7) | 0;
|
||||
address = ((address | 0) - (yOffset | 0)) | 0;
|
||||
}
|
||||
//Copy out our pixels:
|
||||
this.render4BitVRAM(chrData >> 8, address | 0);
|
||||
}
|
||||
if (__LITTLE_ENDIAN__) {
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.render4BitVRAM = function (chrData, address) {
|
||||
chrData = chrData | 0;
|
||||
address = address | 0;
|
||||
//Unrolled data tile line fetch:
|
||||
if ((address | 0) < 0x4000) {
|
||||
//Tile address valid:
|
||||
var paletteOffset = chrData & 0xF0;
|
||||
var data = this.VRAM32[address | 0] | 0;
|
||||
if ((chrData & 0x4) == 0) {
|
||||
//Normal Horizontal:
|
||||
this.tileFetched[0] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[1] = this.palette16[paletteOffset | ((data >> 4) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[2] = this.palette16[paletteOffset | ((data >> 8) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[3] = this.palette16[paletteOffset | ((data >> 12) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[4] = this.palette16[paletteOffset | ((data >> 16) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[5] = this.palette16[paletteOffset | ((data >> 20) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[6] = this.palette16[paletteOffset | ((data >> 24) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[7] = this.palette16[paletteOffset | (data >>> 28)] | this.priorityFlag;
|
||||
}
|
||||
else {
|
||||
//Flipped Horizontally:
|
||||
this.tileFetched[0] = this.palette16[paletteOffset | (data >>> 28)] | this.priorityFlag;
|
||||
this.tileFetched[1] = this.palette16[paletteOffset | ((data >> 24) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[2] = this.palette16[paletteOffset | ((data >> 20) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[3] = this.palette16[paletteOffset | ((data >> 16) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[4] = this.palette16[paletteOffset | ((data >> 12) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[5] = this.palette16[paletteOffset | ((data >> 8) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[6] = this.palette16[paletteOffset | ((data >> 4) & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[7] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Tile address invalid:
|
||||
this.addressInvalidRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.render4BitVRAM = function (chrData, address) {
|
||||
address <<= 2;
|
||||
//Unrolled data tile line fetch:
|
||||
if (address < 0x10000) {
|
||||
//Tile address valid:
|
||||
var paletteOffset = chrData & 0xF0;
|
||||
var data = this.VRAM[address];
|
||||
if ((chrData & 0x4) == 0) {
|
||||
//Normal Horizontal:
|
||||
this.tileFetched[0] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[1] = this.palette16[paletteOffset | (data >> 4)] | this.priorityFlag;
|
||||
data = this.VRAM[address | 1];
|
||||
this.tileFetched[2] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[3] = this.palette16[paletteOffset | (data >> 4)] | this.priorityFlag;
|
||||
data = this.VRAM[address | 2];
|
||||
this.tileFetched[4] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[5] = this.palette16[paletteOffset | (data >> 4)] | this.priorityFlag;
|
||||
data = this.VRAM[address | 3];
|
||||
this.tileFetched[6] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[7] = this.palette16[paletteOffset | (data >> 4)] | this.priorityFlag;
|
||||
}
|
||||
else {
|
||||
//Flipped Horizontally:
|
||||
this.tileFetched[7] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[6] = this.palette16[paletteOffset | (data >> 4)] | this.priorityFlag;
|
||||
data = this.VRAM[address | 1];
|
||||
this.tileFetched[5] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[4] = this.palette16[paletteOffset | (data >> 4)] | this.priorityFlag;
|
||||
data = this.VRAM[address | 2];
|
||||
this.tileFetched[3] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[2] = this.palette16[paletteOffset | (data >> 4)] | this.priorityFlag;
|
||||
data = this.VRAM[address | 3];
|
||||
this.tileFetched[1] = this.palette16[paletteOffset | (data & 0xF)] | this.priorityFlag;
|
||||
this.tileFetched[0] = this.palette16[paletteOffset | (data >> 4)] | this.priorityFlag;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Tile address invalid:
|
||||
this.addressInvalidRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
If there was 64 bit typed array support,
|
||||
then process8BitVRAM, render8BitVRAMNormal,
|
||||
and render8BitVRAMFlipped could be optimized further.
|
||||
Namely make one fetch for tile data instead of two,
|
||||
and cancel a y-offset shift.
|
||||
*/
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.process8BitVRAM = function (chrData, yOffset) {
|
||||
//16 color tile mode:
|
||||
chrData = chrData | 0;
|
||||
yOffset = yOffset | 0;
|
||||
//Parse flip attributes, grab palette, and then output pixel:
|
||||
var address = (chrData & 0x3FF) << 4;
|
||||
address = ((address | 0) + (this.BGCharacterBaseBlock | 0)) | 0;
|
||||
//Copy out our pixels:
|
||||
switch (chrData & 0xC00) {
|
||||
//No Flip:
|
||||
case 0:
|
||||
address = ((address | 0) + (yOffset << 1)) | 0;
|
||||
this.render8BitVRAMNormal(address | 0);
|
||||
break;
|
||||
//Horizontal Flip:
|
||||
case 0x400:
|
||||
address = ((address | 0) + (yOffset << 1)) | 0;
|
||||
this.render8BitVRAMFlipped(address | 0);
|
||||
break;
|
||||
//Vertical Flip:
|
||||
case 0x800:
|
||||
address = ((address | 0) + 14) | 0;
|
||||
address = ((address | 0) - (yOffset << 1)) | 0;
|
||||
this.render8BitVRAMNormal(address | 0);
|
||||
break;
|
||||
//Horizontal & Vertical Flip:
|
||||
default:
|
||||
address = ((address | 0) + 14) | 0;
|
||||
address = ((address | 0) - (yOffset << 1)) | 0;
|
||||
this.render8BitVRAMFlipped(address | 0);
|
||||
}
|
||||
}
|
||||
if (__LITTLE_ENDIAN__) {
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.render8BitVRAMNormal = function (address) {
|
||||
address = address | 0;
|
||||
if ((address | 0) < 0x4000) {
|
||||
//Tile address valid:
|
||||
//Normal Horizontal:
|
||||
var data = this.VRAM32[address | 0] | 0;
|
||||
this.tileFetched[0] = this.palette256[data & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[1] = this.palette256[(data >> 8) & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[2] = this.palette256[(data >> 16) & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[3] = this.palette256[data >>> 24] | this.priorityFlag;
|
||||
data = this.VRAM32[address | 1] | 0;
|
||||
this.tileFetched[4] = this.palette256[data & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[5] = this.palette256[(data >> 8) & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[6] = this.palette256[(data >> 16) & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[7] = this.palette256[data >>> 24] | this.priorityFlag;
|
||||
}
|
||||
else {
|
||||
//Tile address invalid:
|
||||
this.addressInvalidRender();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.render8BitVRAMFlipped = function (address) {
|
||||
address = address | 0;
|
||||
if ((address | 0) < 0x4000) {
|
||||
//Tile address valid:
|
||||
//Flipped Horizontally:
|
||||
var data = this.VRAM32[address | 0] | 0;
|
||||
this.tileFetched[4] = this.palette256[data >>> 24] | this.priorityFlag;
|
||||
this.tileFetched[5] = this.palette256[(data >> 16) & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[6] = this.palette256[(data >> 8) & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[7] = this.palette256[data & 0xFF] | this.priorityFlag;
|
||||
data = this.VRAM32[address | 1] | 0;
|
||||
this.tileFetched[0] = this.palette256[data >>> 24] | this.priorityFlag;
|
||||
this.tileFetched[1] = this.palette256[(data >> 16) & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[2] = this.palette256[(data >> 8) & 0xFF] | this.priorityFlag;
|
||||
this.tileFetched[3] = this.palette256[data & 0xFF] | this.priorityFlag;
|
||||
}
|
||||
else {
|
||||
//Tile address invalid:
|
||||
this.addressInvalidRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.render8BitVRAMNormal = function (address) {
|
||||
address <<= 2;
|
||||
if (address < 0x10000) {
|
||||
//Tile address valid:
|
||||
//Normal Horizontal:
|
||||
this.tileFetched[0] = this.palette256[this.VRAM[address]] | this.priorityFlag;
|
||||
this.tileFetched[1] = this.palette256[this.VRAM[address | 1]] | this.priorityFlag;
|
||||
this.tileFetched[2] = this.palette256[this.VRAM[address | 2]] | this.priorityFlag;
|
||||
this.tileFetched[3] = this.palette256[this.VRAM[address | 3]] | this.priorityFlag;
|
||||
this.tileFetched[4] = this.palette256[this.VRAM[address | 4]] | this.priorityFlag;
|
||||
this.tileFetched[5] = this.palette256[this.VRAM[address | 5]] | this.priorityFlag;
|
||||
this.tileFetched[6] = this.palette256[this.VRAM[address | 6]] | this.priorityFlag;
|
||||
this.tileFetched[7] = this.palette256[this.VRAM[address | 7]] | this.priorityFlag;
|
||||
}
|
||||
else {
|
||||
//Tile address invalid:
|
||||
this.addressInvalidRender();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.render8BitVRAMFlipped = function (address) {
|
||||
address <<= 2;
|
||||
if (address < 0x10000) {
|
||||
//Tile address valid:
|
||||
//Flipped Horizontally:
|
||||
this.tileFetched[7] = this.palette256[this.VRAM[address]] | this.priorityFlag;
|
||||
this.tileFetched[6] = this.palette256[this.VRAM[address | 1]] | this.priorityFlag;
|
||||
this.tileFetched[5] = this.palette256[this.VRAM[address | 2]] | this.priorityFlag;
|
||||
this.tileFetched[4] = this.palette256[this.VRAM[address | 3]] | this.priorityFlag;
|
||||
this.tileFetched[3] = this.palette256[this.VRAM[address | 4]] | this.priorityFlag;
|
||||
this.tileFetched[2] = this.palette256[this.VRAM[address | 5]] | this.priorityFlag;
|
||||
this.tileFetched[1] = this.palette256[this.VRAM[address | 6]] | this.priorityFlag;
|
||||
this.tileFetched[0] = this.palette256[this.VRAM[address | 7]] | this.priorityFlag;
|
||||
}
|
||||
else {
|
||||
//Tile address invalid:
|
||||
this.addressInvalidRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.addressInvalidRender = function () {
|
||||
//In GBA mode on NDS, we display transparency on invalid tiles:
|
||||
var data = this.gfx.transparency | this.priorityFlag;
|
||||
this.tileFetched[0] = data | 0;
|
||||
this.tileFetched[1] = data | 0;
|
||||
this.tileFetched[2] = data | 0;
|
||||
this.tileFetched[3] = data | 0;
|
||||
this.tileFetched[4] = data | 0;
|
||||
this.tileFetched[5] = data | 0;
|
||||
this.tileFetched[6] = data | 0;
|
||||
this.tileFetched[7] = data | 0;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.setMosaicEnable = function (doMosaic) {
|
||||
doMosaic = doMosaic | 0;
|
||||
this.doMosaic = doMosaic | 0;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.paletteModeSelect = function (do256) {
|
||||
do256 = do256 | 0;
|
||||
this.do256 = do256 | 0;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.screenSizePreprocess = function (BGScreenSize) {
|
||||
BGScreenSize = BGScreenSize | 0;
|
||||
this.tileMode = BGScreenSize | 0;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.priorityPreprocess = function (BGPriority) {
|
||||
BGPriority = BGPriority | 0;
|
||||
this.priorityFlag = (BGPriority << 23) | (1 << (this.BGLayer | 0x10));
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.screenBaseBlockPreprocess = function (BGScreenBaseBlock) {
|
||||
BGScreenBaseBlock = BGScreenBaseBlock | 0;
|
||||
this.BGScreenBaseBlock = BGScreenBaseBlock << 10;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.characterBaseBlockPreprocess = function (BGCharacterBaseBlock) {
|
||||
BGCharacterBaseBlock = BGCharacterBaseBlock | 0;
|
||||
this.BGCharacterBaseBlock = BGCharacterBaseBlock << 12;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGCNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.setMosaicEnable(data & 0x40);
|
||||
this.paletteModeSelect(data & 0x80);
|
||||
this.priorityPreprocess(data & 0x3);
|
||||
this.characterBaseBlockPreprocess((data & 0xC) >> 2);
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGCNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.screenSizePreprocess((data & 0xC0) >> 6);
|
||||
this.screenBaseBlockPreprocess(data & 0x1F);
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGCNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.setMosaicEnable(data & 0x40);
|
||||
this.paletteModeSelect(data & 0x80);
|
||||
this.priorityPreprocess(data & 0x3);
|
||||
this.characterBaseBlockPreprocess((data & 0xC) >> 2);
|
||||
this.screenSizePreprocess((data & 0xC000) >> 14);
|
||||
this.screenBaseBlockPreprocess((data >> 8) & 0x1F);
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGHOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGXCoord = (this.BGXCoord & 0x100) | data;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGHOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGXCoord = (data << 8) | (this.BGXCoord & 0xFF);
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGHOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGXCoord = data | 0;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGVOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGYCoord = (this.BGYCoord & 0x100) | data;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGVOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGYCoord = (data << 8) | (this.BGYCoord & 0xFF);
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGVOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGYCoord = data | 0;
|
||||
}
|
||||
GameBoyAdvanceBGTEXTRenderer.prototype.writeBGOFS32 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGXCoord = data & 0x1FF;
|
||||
this.BGYCoord = data >> 16;
|
||||
}
|
347
public/gfiles/gba/IodineGBA/core/graphics/ColorEffects.js
Normal file
347
public/gfiles/gba/IodineGBA/core/graphics/ColorEffects.js
Normal file
|
@ -0,0 +1,347 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceColorEffectsRenderer(buffer) {
|
||||
this.effectsTarget1 = 0;
|
||||
this.colorEffectsType = 0;
|
||||
this.effectsTarget2 = 0;
|
||||
this.initialize(buffer);
|
||||
}
|
||||
if (typeof SIMD == "object" && typeof SIMD.Int32x4 == "function") {
|
||||
//SIMD support found, insert the optimized SIMD path in:
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.initialize = function (buffer) {
|
||||
this.alphaBlendAmountTarget1 = SIMD.Int32x4.splat(0);
|
||||
this.alphaBlendAmountTarget2 = SIMD.Int32x4.splat(0);
|
||||
this.brightnessEffectAmount = SIMD.Int32x4.splat(0);
|
||||
this.brightnessEffectAmountReverse = SIMD.Int32x4.splat(0x10);
|
||||
this.buffer = buffer;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.pixelMask = SIMD.Int32x4.splat(0x1F);
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.temporaryPixelBuffer = new Int32Array(4);
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.alphaBlend = function (topPixel, lowerPixel) {
|
||||
topPixel = topPixel | 0;
|
||||
lowerPixel = lowerPixel | 0;
|
||||
var p1 = SIMD.Int32x4(topPixel >> 10, topPixel >> 5, topPixel, 0);
|
||||
var p2 = SIMD.Int32x4(lowerPixel >> 10, lowerPixel >> 5, lowerPixel, 0);
|
||||
p1 = SIMD.Int32x4.and(p1, this.pixelMask);
|
||||
p2 = SIMD.Int32x4.and(p2, this.pixelMask);
|
||||
p1 = SIMD.Int32x4.mul(p1, this.alphaBlendAmountTarget1);
|
||||
p2 = SIMD.Int32x4.mul(p2, this.alphaBlendAmountTarget2);
|
||||
var presult = SIMD.Int32x4.add(p1, p2);
|
||||
presult = SIMD.Int32x4.shiftRightByScalar(presult, 4);
|
||||
var selectMask = SIMD.Int32x4.lessThanOrEqual(presult, this.pixelMask);
|
||||
presult = SIMD.Int32x4.select(selectMask, presult, this.pixelMask);
|
||||
SIMD.Int32x4.store(this.temporaryPixelBuffer, 0, presult);
|
||||
return (this.temporaryPixelBuffer[0] << 10) | (this.temporaryPixelBuffer[1] << 5) | this.temporaryPixelBuffer[2];
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.brightnessIncrease = function (topPixel) {
|
||||
topPixel = topPixel | 0;
|
||||
var p1 = SIMD.Int32x4(topPixel >> 10, topPixel >> 5, topPixel, 0);
|
||||
p1 = SIMD.Int32x4.and(p1, this.pixelMask);
|
||||
var pTemp = SIMD.Int32x4.sub(this.pixelMask, p1);
|
||||
pTemp = SIMD.Int32x4.mul(pTemp, this.brightnessEffectAmount);
|
||||
pTemp = SIMD.Int32x4.shiftRightByScalar(pTemp, 4);
|
||||
p1 = SIMD.Int32x4.add(p1, pTemp);
|
||||
SIMD.Int32x4.store(this.temporaryPixelBuffer, 0, p1);
|
||||
return (this.temporaryPixelBuffer[0] << 10) | (this.temporaryPixelBuffer[1] << 5) | this.temporaryPixelBuffer[2];
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.brightnessDecrease = function (topPixel) {
|
||||
topPixel = topPixel | 0;
|
||||
var p1 = SIMD.Int32x4(topPixel >> 10, topPixel >> 5, topPixel, 0);
|
||||
p1 = SIMD.Int32x4.and(p1, this.pixelMask);
|
||||
p1 = SIMD.Int32x4.mul(p1, this.brightnessEffectAmountReverse);
|
||||
p1 = SIMD.Int32x4.shiftRightByScalar(p1, 4);
|
||||
SIMD.Int32x4.store(this.temporaryPixelBuffer, 0, p1);
|
||||
return (this.temporaryPixelBuffer[0] << 10) | (this.temporaryPixelBuffer[1] << 5) | this.temporaryPixelBuffer[2];
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDALPHA8_0 = function (data) {
|
||||
data = data | 0;
|
||||
var alphaBlendAmountTarget1Scratch = data & 0x1F;
|
||||
this.alphaBlendAmountTarget1 = SIMD.Int32x4.splat(Math.min(alphaBlendAmountTarget1Scratch | 0, 0x10) | 0);
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDALPHA8_1 = function (data) {
|
||||
data = data | 0;
|
||||
var alphaBlendAmountTarget2Scratch = data & 0x1F;
|
||||
this.alphaBlendAmountTarget2 = SIMD.Int32x4.splat(Math.min(alphaBlendAmountTarget2Scratch | 0, 0x10) | 0);
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDALPHA16 = function (data) {
|
||||
data = data | 0;
|
||||
var alphaBlendAmountTarget1Scratch = data & 0x1F;
|
||||
this.alphaBlendAmountTarget1 = SIMD.Int32x4.splat(Math.min(alphaBlendAmountTarget1Scratch | 0, 0x10) | 0);
|
||||
var alphaBlendAmountTarget2Scratch = (data >> 8) & 0x1F;
|
||||
this.alphaBlendAmountTarget2 = SIMD.Int32x4.splat(Math.min(alphaBlendAmountTarget2Scratch | 0, 0x10) | 0);
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDCNT32 = function (data) {
|
||||
data = data | 0;
|
||||
//Select target 1 and color effects mode:
|
||||
this.effectsTarget1 = (data & 0x3F) << 16;
|
||||
this.colorEffectsType = (data >> 6) & 0x3;
|
||||
//Select target 2:
|
||||
this.effectsTarget2 = (data & 0x3F00) << 8;
|
||||
var alphaBlendAmountTarget1Scratch = (data >> 16) & 0x1F;
|
||||
this.alphaBlendAmountTarget1 = SIMD.Int32x4.splat(Math.min(alphaBlendAmountTarget1Scratch | 0, 0x10) | 0);
|
||||
var alphaBlendAmountTarget2Scratch = (data >> 24) & 0x1F;
|
||||
this.alphaBlendAmountTarget2 = SIMD.Int32x4.splat(Math.min(alphaBlendAmountTarget2Scratch | 0, 0x10) | 0);
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDY8 = function (data) {
|
||||
data = data | 0;
|
||||
var data = Math.min(data & 0x1F, 0x10) | 0;
|
||||
this.brightnessEffectAmount = SIMD.Int32x4.splat(data | 0);
|
||||
this.brightnessEffectAmountReverse = SIMD.Int32x4.splat((0x10 - (data | 0)) | 0);
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processFullNormalEffectsNoSprites = function () {
|
||||
for (var index = 0; (index | 0) < 240; index = ((index | 0) + 4) | 0) {
|
||||
this.buffer[index | 0] = this.processPixelNormal(this.buffer[index | 0x700] | 0, this.buffer[index | 0x800] | 0);
|
||||
this.buffer[index | 1] = this.processPixelNormal(this.buffer[index | 0x701] | 0, this.buffer[index | 0x801] | 0);
|
||||
this.buffer[index | 2] = this.processPixelNormal(this.buffer[index | 0x702] | 0, this.buffer[index | 0x802] | 0);
|
||||
this.buffer[index | 3] = this.processPixelNormal(this.buffer[index | 0x703] | 0, this.buffer[index | 0x803] | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processWindowNormalEffectsNoSprites = function (xStart, xEnd) {
|
||||
xStart = xStart | 0;
|
||||
xEnd = xEnd | 0;
|
||||
while ((xStart | 0) < (xEnd | 0)) {
|
||||
this.buffer[xStart | 0] = this.processPixelNormal(this.buffer[xStart | 0x700] | 0, this.buffer[xStart | 0x800] | 0);
|
||||
xStart = ((xStart | 0) + 1) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processFullNormalEffectsWithSprites = function () {
|
||||
for (var index = 0; (index | 0) < 240; index = ((index | 0) + 4) | 0) {
|
||||
this.buffer[index | 0] = this.processPixelTestFull(this.buffer[index | 0x700] | 0, this.buffer[index | 0x800] | 0);
|
||||
this.buffer[index | 1] = this.processPixelTestFull(this.buffer[index | 0x701] | 0, this.buffer[index | 0x801] | 0);
|
||||
this.buffer[index | 2] = this.processPixelTestFull(this.buffer[index | 0x702] | 0, this.buffer[index | 0x802] | 0);
|
||||
this.buffer[index | 3] = this.processPixelTestFull(this.buffer[index | 0x703] | 0, this.buffer[index | 0x803] | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processWindowNormalEffectsWithSprites = function (xStart, xEnd) {
|
||||
xStart = xStart | 0;
|
||||
xEnd = xEnd | 0;
|
||||
while ((xStart | 0) < (xEnd | 0)) {
|
||||
this.buffer[xStart | 0] = this.processPixelTestFull(this.buffer[xStart | 0x700] | 0, this.buffer[xStart | 0x800] | 0);
|
||||
xStart = ((xStart | 0) + 1) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processFullNoEffectsWithSprites = function () {
|
||||
for (var index = 0; (index | 0) < 240; index = ((index | 0) + 4) | 0) {
|
||||
this.buffer[index | 0] = this.processPixelTestSprite(this.buffer[index | 0x700] | 0, this.buffer[index | 0x800] | 0);
|
||||
this.buffer[index | 1] = this.processPixelTestSprite(this.buffer[index | 0x701] | 0, this.buffer[index | 0x801] | 0);
|
||||
this.buffer[index | 2] = this.processPixelTestSprite(this.buffer[index | 0x702] | 0, this.buffer[index | 0x802] | 0);
|
||||
this.buffer[index | 3] = this.processPixelTestSprite(this.buffer[index | 0x703] | 0, this.buffer[index | 0x803] | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processWindowNoEffectsWithSprites = function (xStart, xEnd) {
|
||||
xStart = xStart | 0;
|
||||
xEnd = xEnd | 0;
|
||||
while ((xStart | 0) < (xEnd | 0)) {
|
||||
this.buffer[xStart | 0] = this.processPixelTestSprite(this.buffer[xStart | 0x700] | 0, this.buffer[xStart | 0x800] | 0);
|
||||
xStart = ((xStart | 0) + 1) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processPixelTestFull = function (lowerPixel, currentPixel) {
|
||||
lowerPixel = lowerPixel | 0;
|
||||
currentPixel = currentPixel | 0;
|
||||
if ((currentPixel & 0x400000) == 0) {
|
||||
return this.processPixelNormal(lowerPixel | 0, currentPixel | 0) | 0;
|
||||
}
|
||||
else {
|
||||
return this.processPixelSprite(lowerPixel | 0, currentPixel | 0) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processPixelTestSprite = function (lowerPixel, currentPixel) {
|
||||
lowerPixel = lowerPixel | 0;
|
||||
currentPixel = currentPixel | 0;
|
||||
if ((currentPixel & 0x400000) == 0) {
|
||||
return currentPixel | 0;
|
||||
}
|
||||
else {
|
||||
return this.processPixelSprite(lowerPixel | 0, currentPixel | 0) | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//No SIMD support found, use the scalar path instead:
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.initialize = function (buffer) {
|
||||
this.alphaBlendAmountTarget1 = 0;
|
||||
this.alphaBlendAmountTarget2 = 0;
|
||||
this.brightnessEffectAmount = 0;
|
||||
}
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.alphaBlend = function (topPixel, lowerPixel) {
|
||||
topPixel = topPixel | 0;
|
||||
lowerPixel = lowerPixel | 0;
|
||||
var b1 = (topPixel >> 10) & 0x1F;
|
||||
var g1 = (topPixel >> 5) & 0x1F;
|
||||
var r1 = topPixel & 0x1F;
|
||||
var b2 = (lowerPixel >> 10) & 0x1F;
|
||||
var g2 = (lowerPixel >> 5) & 0x1F;
|
||||
var r2 = lowerPixel & 0x1F;
|
||||
b1 = Math.imul(b1 | 0, this.alphaBlendAmountTarget1 | 0) | 0;
|
||||
g1 = Math.imul(g1 | 0, this.alphaBlendAmountTarget1 | 0) | 0;
|
||||
r1 = Math.imul(r1 | 0, this.alphaBlendAmountTarget1 | 0) | 0;
|
||||
b2 = Math.imul(b2 | 0, this.alphaBlendAmountTarget2 | 0) | 0;
|
||||
g2 = Math.imul(g2 | 0, this.alphaBlendAmountTarget2 | 0) | 0;
|
||||
r2 = Math.imul(r2 | 0, this.alphaBlendAmountTarget2 | 0) | 0;
|
||||
//Keep this not inlined in the return, firefox 22 grinds on it:
|
||||
var b = Math.min(((b1 | 0) + (b2 | 0)) >> 4, 0x1F) | 0;
|
||||
var g = Math.min(((g1 | 0) + (g2 | 0)) >> 4, 0x1F) | 0;
|
||||
var r = Math.min(((r1 | 0) + (r2 | 0)) >> 4, 0x1F) | 0;
|
||||
return (b << 10) | (g << 5) | r;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.brightnessIncrease = function (topPixel) {
|
||||
topPixel = topPixel | 0;
|
||||
var b1 = (topPixel >> 10) & 0x1F;
|
||||
var g1 = (topPixel >> 5) & 0x1F;
|
||||
var r1 = topPixel & 0x1F;
|
||||
b1 = ((b1 | 0) + (Math.imul((0x1F - (b1 | 0)) | 0, this.brightnessEffectAmount | 0) >> 4)) | 0;
|
||||
g1 = ((g1 | 0) + (Math.imul((0x1F - (g1 | 0)) | 0, this.brightnessEffectAmount | 0) >> 4)) | 0;
|
||||
r1 = ((r1 | 0) + (Math.imul((0x1F - (r1 | 0)) | 0, this.brightnessEffectAmount | 0) >> 4)) | 0;
|
||||
return (b1 << 10) | (g1 << 5) | r1;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.brightnessDecrease = function (topPixel) {
|
||||
topPixel = topPixel | 0;
|
||||
var b1 = (topPixel >> 10) & 0x1F;
|
||||
var g1 = (topPixel >> 5) & 0x1F;
|
||||
var r1 = topPixel & 0x1F;
|
||||
var decreaseMultiplier = (0x10 - (this.brightnessEffectAmount | 0)) | 0;
|
||||
b1 = Math.imul(b1 | 0, decreaseMultiplier | 0) >> 4;
|
||||
g1 = Math.imul(g1 | 0, decreaseMultiplier | 0) >> 4;
|
||||
r1 = Math.imul(r1 | 0, decreaseMultiplier | 0) >> 4;
|
||||
return (b1 << 10) | (g1 << 5) | r1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.alphaBlend = function (topPixel, lowerPixel) {
|
||||
topPixel = topPixel | 0;
|
||||
lowerPixel = lowerPixel | 0;
|
||||
var b1 = (topPixel >> 10) & 0x1F;
|
||||
var g1 = (topPixel >> 5) & 0x1F;
|
||||
var r1 = (topPixel & 0x1F);
|
||||
var b2 = (lowerPixel >> 10) & 0x1F;
|
||||
var g2 = (lowerPixel >> 5) & 0x1F;
|
||||
var r2 = lowerPixel & 0x1F;
|
||||
b1 = b1 * this.alphaBlendAmountTarget1;
|
||||
g1 = g1 * this.alphaBlendAmountTarget1;
|
||||
r1 = r1 * this.alphaBlendAmountTarget1;
|
||||
b2 = b2 * this.alphaBlendAmountTarget2;
|
||||
g2 = g2 * this.alphaBlendAmountTarget2;
|
||||
r2 = r2 * this.alphaBlendAmountTarget2;
|
||||
return (Math.min((b1 + b2) >> 4, 0x1F) << 10) | (Math.min((g1 + g2) >> 4, 0x1F) << 5) | Math.min((r1 + r2) >> 4, 0x1F);
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.brightnessIncrease = function (topPixel) {
|
||||
topPixel = topPixel | 0;
|
||||
var b1 = (topPixel >> 10) & 0x1F;
|
||||
var g1 = (topPixel >> 5) & 0x1F;
|
||||
var r1 = topPixel & 0x1F;
|
||||
b1 += ((0x1F - b1) * this.brightnessEffectAmount) >> 4;
|
||||
g1 += ((0x1F - g1) * this.brightnessEffectAmount) >> 4;
|
||||
r1 += ((0x1F - r1) * this.brightnessEffectAmount) >> 4;
|
||||
return (b1 << 10) | (g1 << 5) | r1;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.brightnessDecrease = function (topPixel) {
|
||||
topPixel = topPixel | 0;
|
||||
var b1 = (topPixel >> 10) & 0x1F;
|
||||
var g1 = (topPixel >> 5) & 0x1F;
|
||||
var r1 = topPixel & 0x1F;
|
||||
var decreaseMultiplier = 0x10 - this.brightnessEffectAmount;
|
||||
b1 = (b1 * decreaseMultiplier) >> 4;
|
||||
g1 = (g1 * decreaseMultiplier) >> 4;
|
||||
r1 = (r1 * decreaseMultiplier) >> 4;
|
||||
return (b1 << 10) | (g1 << 5) | r1;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDALPHA8_0 = function (data) {
|
||||
data = data | 0;
|
||||
var alphaBlendAmountTarget1Scratch = data & 0x1F;
|
||||
this.alphaBlendAmountTarget1 = Math.min(alphaBlendAmountTarget1Scratch | 0, 0x10) | 0;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDALPHA8_1 = function (data) {
|
||||
data = data | 0;
|
||||
var alphaBlendAmountTarget2Scratch = data & 0x1F;
|
||||
this.alphaBlendAmountTarget2 = Math.min(alphaBlendAmountTarget2Scratch | 0, 0x10) | 0;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDALPHA16 = function (data) {
|
||||
data = data | 0;
|
||||
var alphaBlendAmountTarget1Scratch = data & 0x1F;
|
||||
this.alphaBlendAmountTarget1 = Math.min(alphaBlendAmountTarget1Scratch | 0, 0x10) | 0;
|
||||
var alphaBlendAmountTarget2Scratch = (data >> 8) & 0x1F;
|
||||
this.alphaBlendAmountTarget2 = Math.min(alphaBlendAmountTarget2Scratch | 0, 0x10) | 0;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDCNT32 = function (data) {
|
||||
data = data | 0;
|
||||
//Select target 1 and color effects mode:
|
||||
this.effectsTarget1 = (data & 0x3F) << 16;
|
||||
this.colorEffectsType = (data >> 6) & 0x3;
|
||||
//Select target 2:
|
||||
this.effectsTarget2 = (data & 0x3F00) << 8;
|
||||
var alphaBlendAmountTarget1Scratch = (data >> 16) & 0x1F;
|
||||
this.alphaBlendAmountTarget1 = Math.min(alphaBlendAmountTarget1Scratch | 0, 0x10) | 0;
|
||||
var alphaBlendAmountTarget2Scratch = (data >> 24) & 0x1F;
|
||||
this.alphaBlendAmountTarget2 = Math.min(alphaBlendAmountTarget2Scratch | 0, 0x10) | 0;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDY8 = function (data) {
|
||||
data = data | 0;
|
||||
this.brightnessEffectAmount = Math.min(data & 0x1F, 0x10) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processPixelNormal = function (lowerPixel, topPixel) {
|
||||
lowerPixel = lowerPixel | 0;
|
||||
topPixel = topPixel | 0;
|
||||
if (((topPixel | 0) & (this.effectsTarget1 | 0)) != 0) {
|
||||
switch (this.colorEffectsType | 0) {
|
||||
case 1:
|
||||
if (((lowerPixel | 0) & (this.effectsTarget2 | 0)) != 0 && (topPixel | 0) != (lowerPixel | 0)) {
|
||||
return this.alphaBlend(topPixel | 0, lowerPixel | 0) | 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
return this.brightnessIncrease(topPixel | 0) | 0;
|
||||
case 3:
|
||||
return this.brightnessDecrease(topPixel | 0) | 0;
|
||||
}
|
||||
}
|
||||
return topPixel | 0;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.processPixelSprite = function (lowerPixel, topPixel) {
|
||||
lowerPixel = lowerPixel | 0;
|
||||
topPixel = topPixel | 0;
|
||||
if (((lowerPixel | 0) & (this.effectsTarget2 | 0)) != 0) {
|
||||
return this.alphaBlend(topPixel | 0, lowerPixel | 0) | 0;
|
||||
}
|
||||
else if (((topPixel | 0) & (this.effectsTarget1 | 0)) != 0) {
|
||||
switch (this.colorEffectsType | 0) {
|
||||
case 2:
|
||||
return this.brightnessIncrease(topPixel | 0) | 0;
|
||||
case 3:
|
||||
return this.brightnessDecrease(topPixel | 0) | 0;
|
||||
}
|
||||
}
|
||||
return topPixel | 0;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDCNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
//Select target 1 and color effects mode:
|
||||
this.effectsTarget1 = (data & 0x3F) << 16;
|
||||
this.colorEffectsType = data >> 6;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDCNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
//Select target 2:
|
||||
this.effectsTarget2 = (data & 0x3F) << 16;
|
||||
}
|
||||
GameBoyAdvanceColorEffectsRenderer.prototype.writeBLDCNT16 = function (data) {
|
||||
data = data | 0;
|
||||
//Select target 1 and color effects mode:
|
||||
this.effectsTarget1 = (data & 0x3F) << 16;
|
||||
this.colorEffectsType = (data >> 6) & 0x3;
|
||||
//Select target 2:
|
||||
this.effectsTarget2 = (data & 0x3F00) << 8;
|
||||
}
|
949
public/gfiles/gba/IodineGBA/core/graphics/Compositor.js
Normal file
949
public/gfiles/gba/IodineGBA/core/graphics/Compositor.js
Normal file
|
@ -0,0 +1,949 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceCompositor(gfx) {
|
||||
this.gfx = gfx;
|
||||
this.doEffects = 0;
|
||||
}
|
||||
function GameBoyAdvanceWindowCompositor(gfx) {
|
||||
this.gfx = gfx;
|
||||
this.doEffects = 0;
|
||||
}
|
||||
function GameBoyAdvanceOBJWindowCompositor(gfx) {
|
||||
this.gfx = gfx;
|
||||
this.doEffects = 0;
|
||||
}
|
||||
GameBoyAdvanceCompositor.prototype.initialize = GameBoyAdvanceWindowCompositor.prototype.initialize = function () {
|
||||
this.buffer = this.gfx.buffer;
|
||||
this.colorEffectsRenderer = this.gfx.colorEffectsRenderer;
|
||||
}
|
||||
GameBoyAdvanceOBJWindowCompositor.prototype.initialize = function () {
|
||||
this.buffer = this.gfx.buffer;
|
||||
this.colorEffectsRenderer = this.gfx.colorEffectsRenderer;
|
||||
this.OBJWindowBuffer = this.gfx.objRenderer.scratchWindowBuffer;
|
||||
}
|
||||
GameBoyAdvanceCompositor.prototype.preprocess = GameBoyAdvanceWindowCompositor.prototype.preprocess = GameBoyAdvanceOBJWindowCompositor.prototype.preprocess = function (doEffects) {
|
||||
doEffects = doEffects | 0;
|
||||
this.doEffects = doEffects | 0;
|
||||
}
|
||||
GameBoyAdvanceOBJWindowCompositor.prototype.renderScanLine = GameBoyAdvanceCompositor.prototype.renderScanLine = function (layers) {
|
||||
layers = layers | 0;
|
||||
if ((this.doEffects | 0) == 0) {
|
||||
this.renderNormalScanLine(layers | 0);
|
||||
}
|
||||
else {
|
||||
this.renderScanLineWithEffects(layers | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWindowCompositor.prototype.renderScanLine = function (xStart, xEnd, layers) {
|
||||
xStart = xStart | 0;
|
||||
xEnd = xEnd | 0;
|
||||
layers = layers | 0;
|
||||
if ((this.doEffects | 0) == 0) {
|
||||
this.renderNormalScanLine(xStart | 0, xEnd | 0, layers | 0);
|
||||
}
|
||||
else {
|
||||
this.renderScanLineWithEffects(xStart | 0, xEnd | 0, layers | 0);
|
||||
}
|
||||
}
|
||||
//Check for SIMD support:
|
||||
if (typeof SIMD == "object" && typeof SIMD.Int32x4 == "function") {
|
||||
GameBoyAdvanceCompositor.prototype.mask0 = SIMD.Int32x4.splat(0);
|
||||
GameBoyAdvanceCompositor.prototype.mask1 = SIMD.Int32x4.splat(0x2000000);
|
||||
GameBoyAdvanceCompositor.prototype.mask2 = SIMD.Int32x4.splat(0x3800000);
|
||||
GameBoyAdvanceCompositor.prototype.mask3 = SIMD.Int32x4.splat(0x1800000);
|
||||
GameBoyAdvanceCompositor.prototype.mask4 = SIMD.Bool32x4.splat(true);
|
||||
}
|
||||
function generateIodineGBAGFXCompositors() {
|
||||
function generateCompositors() {
|
||||
function generateLoop(compositeType, doEffects, layers) {
|
||||
function generateLoopHead(useVectorized, compositeType) {
|
||||
function generateLocalScopeInit(useVectorized, layers, alreadyDeclared) {
|
||||
function checkDeclared(alreadyDeclared) {
|
||||
var code = "";
|
||||
if (!alreadyDeclared) {
|
||||
code += "var ";
|
||||
}
|
||||
return code;
|
||||
}
|
||||
//Declare the necessary temporary variables:
|
||||
var code = "";
|
||||
if (useVectorized) {
|
||||
//Declare the necessary temporary variables:
|
||||
code +=
|
||||
"var backdrop = SIMD.Int32x4.splat(this.gfx.backdrop | 0);";
|
||||
switch (layers) {
|
||||
case 0:
|
||||
//Don't need any if no layers to process:
|
||||
break;
|
||||
default:
|
||||
//Need this temp for more than one layer:
|
||||
code +=
|
||||
checkDeclared(alreadyDeclared) + "workingPixel = this.mask0;" +
|
||||
"var test1 = this.mask4;" +
|
||||
"var test2 = this.mask4;";
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x4:
|
||||
case 0x8:
|
||||
case 0x10:
|
||||
//Need these temps for one or more layers:
|
||||
code +=
|
||||
checkDeclared(alreadyDeclared) + "currentPixel = this.mask0;" +
|
||||
checkDeclared(alreadyDeclared) + "lowerPixel = this.mask0;";
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (layers) {
|
||||
case 0:
|
||||
//Don't need any if no layers to process:
|
||||
break;
|
||||
default:
|
||||
//Need this temp for more than one layer:
|
||||
code +=
|
||||
checkDeclared(alreadyDeclared) + "workingPixel = 0;";
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
case 0x4:
|
||||
case 0x8:
|
||||
case 0x10:
|
||||
//Need these temps for one or more layers:
|
||||
code +=
|
||||
checkDeclared(alreadyDeclared) + "currentPixel = 0;" +
|
||||
checkDeclared(alreadyDeclared) + "lowerPixel = 0;";
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function generateLoopBody(useVectorized, doEffects, layers) {
|
||||
function getSingleLayerPrefix(useVectorized) {
|
||||
//Pass initialization if processing only 1 layer:
|
||||
var code = "";
|
||||
if (useVectorized) {
|
||||
code +=
|
||||
"lowerPixel = backdrop;";
|
||||
}
|
||||
else {
|
||||
code +=
|
||||
"lowerPixel = this.gfx.backdrop | 0;";
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function getMultiLayerPrefix(useVectorized) {
|
||||
//Pass initialization if processing more than 1 layer:
|
||||
var code = "";
|
||||
if (useVectorized) {
|
||||
code +=
|
||||
"lowerPixel = backdrop;" +
|
||||
"currentPixel = lowerPixel;";
|
||||
}
|
||||
else {
|
||||
code +=
|
||||
"lowerPixel = this.gfx.backdrop | 0;" +
|
||||
"currentPixel = lowerPixel | 0;";
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function generateLayerCompareSingle(useVectorized, layerOffset) {
|
||||
//Only 1 layer specified to be rendered:
|
||||
var code = "";
|
||||
if (useVectorized) {
|
||||
code +=
|
||||
"currentPixel = SIMD.Int32x4.load(this.buffer, xStart | " + layerOffset + ");" +
|
||||
"currentPixel = SIMD.Int32x4.select(" +
|
||||
"SIMD.Int32x4.notEqual(" +
|
||||
"this.mask0," +
|
||||
"SIMD.Int32x4.and(currentPixel, this.mask1)" +
|
||||
")," +
|
||||
"lowerPixel," +
|
||||
"currentPixel" +
|
||||
");";
|
||||
}
|
||||
else {
|
||||
code +=
|
||||
"currentPixel = this.buffer[xStart | " + layerOffset + "] | 0;" +
|
||||
"if ((currentPixel & 0x2000000) != 0) {" +
|
||||
"currentPixel = lowerPixel | 0;" +
|
||||
"}";
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function generateLayerCompare(useVectorized, layerOffset) {
|
||||
//Code unit to be used when rendering more than 1 layer:
|
||||
var code = "";
|
||||
if (useVectorized) {
|
||||
code +=
|
||||
"workingPixel = SIMD.Int32x4.load(this.buffer, xStart | " + layerOffset + ");" +
|
||||
"test1 = SIMD.Int32x4.lessThanOrEqual(" +
|
||||
"SIMD.Int32x4.and(workingPixel, this.mask2)," +
|
||||
"SIMD.Int32x4.and(currentPixel, this.mask3)" +
|
||||
");" +
|
||||
"lowerPixel = SIMD.Int32x4.select(test1, currentPixel, lowerPixel);" +
|
||||
"currentPixel = SIMD.Int32x4.select(test1, workingPixel, currentPixel);" +
|
||||
"test2 = SIMD.Int32x4.lessThanOrEqual(" +
|
||||
"SIMD.Int32x4.and(workingPixel, this.mask2)," +
|
||||
"SIMD.Int32x4.and(lowerPixel, this.mask3)" +
|
||||
");" +
|
||||
"lowerPixel = SIMD.Int32x4.select(" +
|
||||
"test1," +
|
||||
"lowerPixel," +
|
||||
"SIMD.Int32x4.select(test2, workingPixel, lowerPixel)" +
|
||||
");";
|
||||
}
|
||||
else {
|
||||
code +=
|
||||
"workingPixel = this.buffer[xStart | " + layerOffset + "] | 0;" +
|
||||
"if ((workingPixel & 0x3800000) <= (currentPixel & 0x1800000)) {" +
|
||||
"lowerPixel = currentPixel | 0;" +
|
||||
"currentPixel = workingPixel | 0;" +
|
||||
"}" +
|
||||
"else if ((workingPixel & 0x3800000) <= (lowerPixel & 0x1800000)) {" +
|
||||
"lowerPixel = workingPixel | 0;" +
|
||||
"}";
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function getColorEffects0Layers(useVectorized, doEffects) {
|
||||
//Handle checks for color effects here:
|
||||
var code = "";
|
||||
if (useVectorized) {
|
||||
//No layers:
|
||||
if (doEffects) {
|
||||
//Color effects enabled:
|
||||
code +=
|
||||
"SIMD.Int32x4.store(this.buffer, xStart | 0x700, this.mask0);" +
|
||||
"SIMD.Int32x4.store(this.buffer, xStart | 0x800, backdrop);";
|
||||
}
|
||||
else {
|
||||
//No effects enabled:
|
||||
code +=
|
||||
"SIMD.Int32x4.store(this.buffer, xStart | 0, backdrop);";
|
||||
}
|
||||
}
|
||||
else {
|
||||
//No layers:
|
||||
if (doEffects) {
|
||||
//Color effects enabled:
|
||||
code +=
|
||||
"this.buffer[xStart | 0] = this.colorEffectsRenderer.processPixelNormal(0, this.gfx.backdrop | 0) | 0;";
|
||||
}
|
||||
else {
|
||||
//No effects enabled:
|
||||
code +=
|
||||
"this.buffer[xStart | 0] = this.gfx.backdrop | 0;"
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function getColorEffectsNoSprites(useVectorized, doEffects) {
|
||||
//Handle checks for color effects here:
|
||||
var code = "";
|
||||
if (useVectorized) {
|
||||
//Rendering with no sprite layer:
|
||||
if (doEffects) {
|
||||
//Color effects enabled:
|
||||
code +=
|
||||
"SIMD.Int32x4.store(this.buffer, xStart | 0x700, lowerPixel);" +
|
||||
"SIMD.Int32x4.store(this.buffer, xStart | 0x800, currentPixel);";
|
||||
}
|
||||
else {
|
||||
//No effects enabled:
|
||||
code +=
|
||||
"SIMD.Int32x4.store(this.buffer, xStart | 0, currentPixel);";
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Rendering with no sprite layer:
|
||||
if (doEffects) {
|
||||
//Color effects enabled:
|
||||
code +=
|
||||
"this.buffer[xStart | 0] = this.colorEffectsRenderer.processPixelNormal(lowerPixel | 0, currentPixel | 0) | 0;";
|
||||
}
|
||||
else {
|
||||
//No effects enabled:
|
||||
code +=
|
||||
"this.buffer[xStart | 0] = currentPixel | 0;";
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function getColorEffectsWithSprites(useVectorized, doEffects) {
|
||||
//Handle checks for color effects here:
|
||||
var code = "";
|
||||
if (useVectorized) {
|
||||
//Rendering with a sprite layer:
|
||||
code +=
|
||||
"SIMD.Int32x4.store(this.buffer, xStart | 0x700, lowerPixel);" +
|
||||
"SIMD.Int32x4.store(this.buffer, xStart | 0x800, currentPixel);";
|
||||
}
|
||||
else {
|
||||
//Rendering with a sprite layer:
|
||||
code +=
|
||||
"if ((currentPixel & 0x400000) == 0) {";
|
||||
if (doEffects) {
|
||||
//Color effects enabled:
|
||||
code +=
|
||||
"this.buffer[xStart | 0] = this.colorEffectsRenderer.processPixelNormal(lowerPixel | 0, currentPixel | 0) | 0;";
|
||||
}
|
||||
else {
|
||||
//No effects enabled:
|
||||
code +=
|
||||
"this.buffer[xStart | 0] = currentPixel | 0;";
|
||||
}
|
||||
code +=
|
||||
"}" +
|
||||
"else {" +
|
||||
//Must handle for semi-transparent sprite case:
|
||||
"this.buffer[xStart | 0] = this.colorEffectsRenderer.processPixelSprite(lowerPixel | 0, currentPixel | 0) | 0;" +
|
||||
"}";
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function generatePass(useVectorized, doEffects, layers) {
|
||||
var code = "";
|
||||
//Special case each possible layer combination:
|
||||
switch (layers) {
|
||||
case 0:
|
||||
//Backdrop only:
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffects0Layers(useVectorized, doEffects);
|
||||
break;
|
||||
case 1:
|
||||
//Generate temps:
|
||||
code += getSingleLayerPrefix(useVectorized);
|
||||
//BG0:
|
||||
code += generateLayerCompareSingle(useVectorized, 0x100);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 2:
|
||||
//Generate temps:
|
||||
code += getSingleLayerPrefix(useVectorized);
|
||||
//BG1:
|
||||
code += generateLayerCompareSingle(useVectorized, 0x200);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 3:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 4:
|
||||
//Generate temps:
|
||||
code += getSingleLayerPrefix(useVectorized);
|
||||
//BG2:
|
||||
code += generateLayerCompareSingle(useVectorized, 0x300);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 5:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 6:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 7:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 8:
|
||||
//Generate temps:
|
||||
code += getSingleLayerPrefix(useVectorized);
|
||||
//BG2:
|
||||
code += generateLayerCompareSingle(useVectorized, 0x400);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 9:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0xA:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0xB:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0xC:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0xD:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0xE:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0xF:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsNoSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x10:
|
||||
//Generate temps:
|
||||
code += getSingleLayerPrefix(useVectorized);
|
||||
//OBJ:
|
||||
code += generateLayerCompareSingle(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x11:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x12:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x13:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x14:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x15:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x16:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x17:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x18:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x19:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x1A:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x1B:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x1C:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x1D:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
case 0x1E:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
break;
|
||||
default:
|
||||
//Generate temps:
|
||||
code += getMultiLayerPrefix(useVectorized);
|
||||
//BG3:
|
||||
code += generateLayerCompare(useVectorized, 0x400);
|
||||
//BG2:
|
||||
code += generateLayerCompare(useVectorized, 0x300);
|
||||
//BG1:
|
||||
code += generateLayerCompare(useVectorized, 0x200);
|
||||
//BG0:
|
||||
code += generateLayerCompare(useVectorized, 0x100);
|
||||
//OBJ:
|
||||
code += generateLayerCompare(useVectorized, 0x500);
|
||||
//Color Effects Post Processing:
|
||||
code += getColorEffectsWithSprites(useVectorized, doEffects);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
//Build the code to put inside a loop:
|
||||
return generatePass(useVectorized, doEffects, layers);
|
||||
}
|
||||
function generateSIMDColorEffectsExternalCall(useVectorized, layers, compositeType) {
|
||||
var code = "";
|
||||
if (useVectorized) {
|
||||
switch (compositeType) {
|
||||
case 0:
|
||||
//Check if we're processing the sprite layer:
|
||||
if (layers < 0x10) {
|
||||
//Don't need color effects processing for the else case:
|
||||
if (doEffects) {
|
||||
//Effects handling:
|
||||
code +=
|
||||
";this.colorEffectsRenderer.processFullNormalEffectsNoSprites()";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (doEffects) {
|
||||
//Effects + semi-transparency handling:
|
||||
code +=
|
||||
";this.colorEffectsRenderer.processFullNormalEffectsWithSprites()";
|
||||
}
|
||||
else {
|
||||
//Sprite semi-transparency handling:
|
||||
code +=
|
||||
";this.colorEffectsRenderer.processFullNoEffectsWithSprites()";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
//Check if we're processing the sprite layer:
|
||||
if (layers < 0x10) {
|
||||
//Don't need color effects processing for the else case:
|
||||
if (doEffects) {
|
||||
//Effects handling:
|
||||
code +=
|
||||
";this.colorEffectsRenderer.processWindowNormalEffectsNoSprites(xStartCopy | 0, xEnd & -4)";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (doEffects) {
|
||||
//Effects + semi-transparency handling:
|
||||
code +=
|
||||
";this.colorEffectsRenderer.processWindowNormalEffectsWithSprites(xStartCopy | 0, xEnd & -4)";
|
||||
}
|
||||
else {
|
||||
//Sprite semi-transparency handling:
|
||||
code +=
|
||||
";this.colorEffectsRenderer.processWindowNoEffectsWithSprites(xStartCopy | 0, xEnd & -4)";
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
var code = "";
|
||||
switch (compositeType) {
|
||||
//Loop for normal compositor:
|
||||
case 0:
|
||||
if (useVectorized) {
|
||||
code +=
|
||||
generateLocalScopeInit(true, layers, false) +
|
||||
"for (var xStart = 0; (xStart | 0) < 240; xStart = ((xStart | 0) + 4) | 0) {" +
|
||||
generateLoopBody(true, doEffects, layers) +
|
||||
"}";
|
||||
}
|
||||
else {
|
||||
code +=
|
||||
generateLocalScopeInit(false, layers, false) +
|
||||
"for (var xStart = 0; (xStart | 0) < 240; xStart = ((xStart | 0) + 1) | 0) {" +
|
||||
generateLoopBody(false, doEffects, layers) +
|
||||
"}";
|
||||
}
|
||||
break;
|
||||
//Loop for window compositor:
|
||||
case 1:
|
||||
code +=
|
||||
"xStart = xStart | 0;" +
|
||||
"xEnd = xEnd | 0;";
|
||||
if (useVectorized) {
|
||||
code +=
|
||||
generateLocalScopeInit(false, layers, false) +
|
||||
"while ((xStart | 0) < (xEnd | 0) && (xStart | 0) <= (xStart | 0x3)) {" +
|
||||
generateLoopBody(false, doEffects, layers) +
|
||||
"xStart = ((xStart | 0) + 1) | 0;" +
|
||||
"}" +
|
||||
"var xStartCopy = xStart | 0;" +
|
||||
generateLocalScopeInit(true, layers, true) +
|
||||
"while ((xStart | 0) < (xEnd & -4)) {" +
|
||||
generateLoopBody(true, doEffects, layers) +
|
||||
"xStart = ((xStart | 0) + 4) | 0;" +
|
||||
"}" +
|
||||
generateLocalScopeInit(false, layers, true) +
|
||||
"while ((xStart | 0) < (xEnd | 0)) {" +
|
||||
generateLoopBody(false, doEffects, layers) +
|
||||
"xStart = ((xStart | 0) + 1) | 0;" +
|
||||
"}";
|
||||
}
|
||||
else {
|
||||
code +=
|
||||
generateLocalScopeInit(false, layers, false) +
|
||||
"while ((xStart | 0) < (xEnd | 0)) {" +
|
||||
generateLoopBody(false, doEffects, layers) +
|
||||
"xStart = ((xStart | 0) + 1) | 0;" +
|
||||
"}";
|
||||
}
|
||||
break;
|
||||
//Loop for OBJ window compositor:
|
||||
case 2:
|
||||
code +=
|
||||
generateLocalScopeInit(false, layers, false) +
|
||||
"for (var xStart = 0; (xStart | 0) < 240; xStart = ((xStart | 0) + 1) | 0) {" +
|
||||
"if ((this.OBJWindowBuffer[xStart | 0] | 0) < 0x3800000) {" +
|
||||
generateLoopBody(false, doEffects, layers) +
|
||||
"}" +
|
||||
"}";
|
||||
}
|
||||
code += generateSIMDColorEffectsExternalCall(useVectorized, layers, compositeType);
|
||||
return code;
|
||||
}
|
||||
//Build the loop:
|
||||
return generateLoopHead(typeof SIMD == "object" && typeof SIMD.Int32x4 == "function", compositeType);
|
||||
}
|
||||
function generateCompositor(compositeType, doEffects) {
|
||||
//Get function suffix we'll use depending on color effects usage:
|
||||
var effectsPrefix = (doEffects) ? "special" : "normal";
|
||||
//Loop through all possible combinations of layers:
|
||||
for (var layers = 0; layers < 0x20; layers++) {
|
||||
//Codegen the loop:
|
||||
var code = generateLoop(compositeType, doEffects, layers);
|
||||
//Compile the code and assign to appropriate compositor object:
|
||||
switch (compositeType) {
|
||||
case 0:
|
||||
//Normal compositor:
|
||||
GameBoyAdvanceCompositor.prototype[effectsPrefix + layers] = Function(code);
|
||||
break;
|
||||
case 1:
|
||||
//Window compositor:
|
||||
GameBoyAdvanceWindowCompositor.prototype[effectsPrefix + layers] = Function("xStart", "xEnd", code);
|
||||
break;
|
||||
default:
|
||||
//OBJ window compositor:
|
||||
GameBoyAdvanceOBJWindowCompositor.prototype[effectsPrefix + layers] = Function(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Build the functions for each of the three compositors:
|
||||
for (var compositeType = 0; compositeType < 3; compositeType++) {
|
||||
//Build for the no special effects processing case:
|
||||
generateCompositor(compositeType, false);
|
||||
//Build for the special effects processing case:
|
||||
generateCompositor(compositeType, true);
|
||||
}
|
||||
}
|
||||
function generateDispatches() {
|
||||
function generateDispatch(coordsSpecified, doEffects) {
|
||||
function generateDispatchBlock(coordsSpecified, doEffects) {
|
||||
function generateDispatchHead(coordsSpecified) {
|
||||
//Initialize some local variables:
|
||||
var code = "";
|
||||
if (coordsSpecified) {
|
||||
code +=
|
||||
"xStart = xStart | 0;" +
|
||||
"xEnd = xEnd | 0;";
|
||||
}
|
||||
code +=
|
||||
"layers = layers | 0;";
|
||||
return code;
|
||||
}
|
||||
function generateDispatchBody(coordsSpecified, doEffects) {
|
||||
function generateSwitchHead(bodyCode) {
|
||||
//We're building a switch statement:
|
||||
var code =
|
||||
"switch (layers | 0) {" +
|
||||
bodyCode +
|
||||
"}";
|
||||
return code;
|
||||
}
|
||||
function generateSwitchBody(coordsSpecified, doEffects) {
|
||||
function generateCases(coordsSpecified, doEffects) {
|
||||
function generateCase(layers, coordsSpecified, doEffects) {
|
||||
function generateCaseHead(layers, bodyCode) {
|
||||
//Building the case label:
|
||||
var code = "";
|
||||
if (layers < 0x1F) {
|
||||
//Not the last case in the list, so specify number:
|
||||
code +=
|
||||
"case " + layers + ":" +
|
||||
"{" +
|
||||
bodyCode + ";" +
|
||||
"break" +
|
||||
"};";
|
||||
}
|
||||
else {
|
||||
//Last case in the list, so place it as default case:
|
||||
code +=
|
||||
"default:" +
|
||||
"{" +
|
||||
bodyCode +
|
||||
"}";
|
||||
}
|
||||
return code;
|
||||
}
|
||||
function generateCaseBody(layers, coordsSpecified, doEffects) {
|
||||
//Build the function call:
|
||||
var code =
|
||||
"this.";
|
||||
if (doEffects) {
|
||||
//Special effects:
|
||||
code +=
|
||||
"special";
|
||||
}
|
||||
else {
|
||||
//No special effects:
|
||||
code +=
|
||||
"normal";
|
||||
}
|
||||
code +=
|
||||
layers +
|
||||
"(";
|
||||
if (coordsSpecified) {
|
||||
//Passing some xcoords as parameters:
|
||||
code +=
|
||||
"xStart | 0, xEnd | 0";
|
||||
}
|
||||
code +=
|
||||
")";
|
||||
return code;
|
||||
}
|
||||
//Build the full case unit:
|
||||
return generateCaseHead(layers, generateCaseBody(layers, coordsSpecified, doEffects));
|
||||
}
|
||||
function generateList(coordsSpecified, doEffects) {
|
||||
var code = "";
|
||||
//Loop through all combinations to build:
|
||||
for (var layers = 0; layers < 0x20; layers++) {
|
||||
//Build a case for the specified combination:
|
||||
code += generateCase(layers, coordsSpecified, doEffects);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
//Build the entire switch:
|
||||
return generateList(coordsSpecified, doEffects);
|
||||
}
|
||||
//Build the entire switch:
|
||||
return generateCases(coordsSpecified, doEffects);
|
||||
}
|
||||
//Build the switch block:
|
||||
return generateSwitchHead(generateSwitchBody(coordsSpecified, doEffects));
|
||||
}
|
||||
function generateDispatchCode(coordsSpecified, doEffects) {
|
||||
//Build the dispatch block:
|
||||
var code = "";
|
||||
code += generateDispatchHead(coordsSpecified);
|
||||
code += generateDispatchBody(coordsSpecified, doEffects);
|
||||
return code;
|
||||
}
|
||||
return generateDispatchCode(coordsSpecified, doEffects);
|
||||
}
|
||||
function generateDispatchFunc(coordsSpecified, code) {
|
||||
if (coordsSpecified) {
|
||||
return Function("xStart", "xEnd", "layers", code);
|
||||
}
|
||||
else {
|
||||
return Function("layers", code);
|
||||
}
|
||||
}
|
||||
//Generate the function:
|
||||
return generateDispatchFunc(coordsSpecified, generateDispatchBlock(coordsSpecified, doEffects));
|
||||
}
|
||||
//Build the functions for each of the six dispatches:
|
||||
GameBoyAdvanceOBJWindowCompositor.prototype.renderNormalScanLine = GameBoyAdvanceCompositor.prototype.renderNormalScanLine = generateDispatch(false, false);
|
||||
GameBoyAdvanceWindowCompositor.prototype.renderNormalScanLine = generateDispatch(true, false);
|
||||
GameBoyAdvanceOBJWindowCompositor.prototype.renderScanLineWithEffects = GameBoyAdvanceCompositor.prototype.renderScanLineWithEffects = generateDispatch(false, true);
|
||||
GameBoyAdvanceWindowCompositor.prototype.renderScanLineWithEffects = generateDispatch(true, true);
|
||||
}
|
||||
//Build and compile the compositors for every possible mode/layer/effect combination:
|
||||
generateCompositors();
|
||||
//Build and compile the dispatches for every possible mode/effect combination:
|
||||
generateDispatches();
|
||||
}
|
||||
generateIodineGBAGFXCompositors();
|
93
public/gfiles/gba/IodineGBA/core/graphics/Mosaic.js
Normal file
93
public/gfiles/gba/IodineGBA/core/graphics/Mosaic.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceMosaicRenderer(buffer) {
|
||||
this.BGMosaicHSize = 0;
|
||||
this.BGMosaicVSize = 0;
|
||||
this.OBJMosaicHSize = 0;
|
||||
this.OBJMosaicVSize = 0;
|
||||
this.buffer = buffer;
|
||||
}
|
||||
GameBoyAdvanceMosaicRenderer.prototype.attachOBJBuffer = function (objBuffer) {
|
||||
//Function only called if no typed array view support:
|
||||
this.objBuffer = objBuffer;
|
||||
}
|
||||
GameBoyAdvanceMosaicRenderer.prototype.renderMosaicHorizontal = function (offset) {
|
||||
offset = offset | 0;
|
||||
var currentPixel = 0;
|
||||
var mosaicBlur = ((this.BGMosaicHSize | 0) + 1) | 0;
|
||||
if ((mosaicBlur | 0) > 1) { //Don't perform a useless loop.
|
||||
for (var position = 0; (position | 0) < 240; position = ((position | 0) + 1) | 0) {
|
||||
if ((((position | 0) % (mosaicBlur | 0)) | 0) == 0) {
|
||||
currentPixel = this.buffer[position | offset] | 0;
|
||||
}
|
||||
else {
|
||||
this.buffer[position | offset] = currentPixel | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (__VIEWS_SUPPORTED__) {
|
||||
GameBoyAdvanceMosaicRenderer.prototype.renderOBJMosaicHorizontal = function (xOffset, xSize) {
|
||||
xOffset = xOffset | 0;
|
||||
xSize = xSize | 0;
|
||||
var currentPixel = 0x3800000;
|
||||
var mosaicBlur = ((this.OBJMosaicHSize | 0) + 1) | 0;
|
||||
if ((mosaicBlur | 0) > 1) { //Don't perform a useless loop.
|
||||
for (var position = ((xOffset | 0) % (mosaicBlur | 0)) | 0; (position | 0) < (xSize | 0); position = ((position | 0) + 1) | 0) {
|
||||
if ((((position | 0) % (mosaicBlur | 0)) | 0) == 0) {
|
||||
currentPixel = this.buffer[position | 0x600] | 0;
|
||||
}
|
||||
this.buffer[position | 0x600] = currentPixel | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameBoyAdvanceMosaicRenderer.prototype.renderOBJMosaicHorizontal = function (xOffset, xSize) {
|
||||
xOffset = xOffset | 0;
|
||||
xSize = xSize | 0;
|
||||
var currentPixel = 0x3800000;
|
||||
var mosaicBlur = ((this.OBJMosaicHSize | 0) + 1) | 0;
|
||||
if ((mosaicBlur | 0) > 1) { //Don't perform a useless loop.
|
||||
for (var position = ((xOffset | 0) % (mosaicBlur | 0)) | 0; (position | 0) < (xSize | 0); position = ((position | 0) + 1) | 0) {
|
||||
if ((((position | 0) % (mosaicBlur | 0)) | 0) == 0) {
|
||||
currentPixel = this.objBuffer[position | 0] | 0;
|
||||
}
|
||||
this.objBuffer[position | 0] = currentPixel | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceMosaicRenderer.prototype.getMosaicYOffset = function (line) {
|
||||
line = line | 0;
|
||||
return ((line | 0) % (((this.BGMosaicVSize | 0) + 1) | 0)) | 0;
|
||||
}
|
||||
GameBoyAdvanceMosaicRenderer.prototype.getOBJMosaicYOffset = function (line) {
|
||||
line = line | 0;
|
||||
return ((line | 0) % (((this.OBJMosaicVSize | 0) + 1) | 0)) | 0;
|
||||
}
|
||||
GameBoyAdvanceMosaicRenderer.prototype.writeMOSAIC8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGMosaicHSize = data & 0xF;
|
||||
this.BGMosaicVSize = data >> 4;
|
||||
}
|
||||
GameBoyAdvanceMosaicRenderer.prototype.writeMOSAIC8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.OBJMosaicHSize = data & 0xF;
|
||||
this.OBJMosaicVSize = data >> 4;
|
||||
}
|
||||
GameBoyAdvanceMosaicRenderer.prototype.writeMOSAIC16 = function (data) {
|
||||
data = data | 0;
|
||||
this.BGMosaicHSize = data & 0xF;
|
||||
this.BGMosaicVSize = (data >> 4) & 0xF;
|
||||
this.OBJMosaicHSize = (data >> 8) & 0xF;
|
||||
this.OBJMosaicVSize = data >> 12;
|
||||
}
|
1024
public/gfiles/gba/IodineGBA/core/graphics/OBJ.js
Normal file
1024
public/gfiles/gba/IodineGBA/core/graphics/OBJ.js
Normal file
File diff suppressed because it is too large
Load diff
41
public/gfiles/gba/IodineGBA/core/graphics/OBJWindow.js
Normal file
41
public/gfiles/gba/IodineGBA/core/graphics/OBJWindow.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceOBJWindowRenderer(compositor) {
|
||||
//Get a layer compositor that we'll send our parameters for windowing to:
|
||||
this.compositor = compositor;
|
||||
}
|
||||
GameBoyAdvanceOBJWindowRenderer.prototype.initialize = function () {
|
||||
//Initialize the compositor:
|
||||
this.compositor.initialize();
|
||||
//Layer masking & color effects control:
|
||||
this.WINOBJOutside = 0;
|
||||
//Need to update the color effects status in the compositor:
|
||||
this.preprocess();
|
||||
}
|
||||
GameBoyAdvanceOBJWindowRenderer.prototype.renderScanLine = function (line, toRender) {
|
||||
line = line | 0;
|
||||
toRender = toRender | 0;
|
||||
//Windowing can disable out further layers:
|
||||
toRender = toRender & this.WINOBJOutside;
|
||||
//Windowing occurs where there is a non-transparent "obj-win" sprite:
|
||||
this.compositor.renderScanLine(toRender | 0);
|
||||
}
|
||||
GameBoyAdvanceOBJWindowRenderer.prototype.writeWINOBJIN8 = function (data) {
|
||||
data = data | 0;
|
||||
//Layer masking & color effects control:
|
||||
this.WINOBJOutside = data | 0;
|
||||
//Need to update the color effects status in the compositor:
|
||||
this.preprocess();
|
||||
}
|
||||
GameBoyAdvanceOBJWindowRenderer.prototype.preprocess = function () {
|
||||
//Update the color effects status in the compositor:
|
||||
this.compositor.preprocess(this.WINOBJOutside & 0x20);
|
||||
}
|
1409
public/gfiles/gba/IodineGBA/core/graphics/Renderer.js
Normal file
1409
public/gfiles/gba/IodineGBA/core/graphics/Renderer.js
Normal file
File diff suppressed because it is too large
Load diff
1253
public/gfiles/gba/IodineGBA/core/graphics/RendererProxy.js
Normal file
1253
public/gfiles/gba/IodineGBA/core/graphics/RendererProxy.js
Normal file
File diff suppressed because it is too large
Load diff
919
public/gfiles/gba/IodineGBA/core/graphics/RendererShim.js
Normal file
919
public/gfiles/gba/IodineGBA/core/graphics/RendererShim.js
Normal file
|
@ -0,0 +1,919 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function getGameBoyAdvanceGraphicsRenderer(coreExposed, skippingBIOS) {
|
||||
if (!coreExposed.offthreadGfxEnabled() || typeof SharedArrayBuffer != "function" || typeof Atomics != "object") {
|
||||
return new GameBoyAdvanceGraphicsRenderer(coreExposed, skippingBIOS);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
//Some browsers don't allow webworkers via file:///
|
||||
return new GameBoyAdvanceGraphicsRendererShim(coreExposed, skippingBIOS);
|
||||
}
|
||||
catch (error) {
|
||||
return new GameBoyAdvanceGraphicsRenderer(coreExposed, skippingBIOS);
|
||||
}
|
||||
}
|
||||
}
|
||||
function GameBoyAdvanceGraphicsRendererShim(coreExposed, skippingBIOS) {
|
||||
this.coreExposed = coreExposed;
|
||||
this.initializeWorker(skippingBIOS);
|
||||
this.appendAtomicSync();
|
||||
this.initializeBuffers();
|
||||
this.shareStaticBuffers();
|
||||
this.shareDynamicBuffers();
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.initializeWorker = function (skippingBIOS) {
|
||||
skippingBIOS = !!skippingBIOS;
|
||||
//Apparently running on localhost is nearly impossible for webworkers in a cross-browser manner:
|
||||
var loc = location.href;
|
||||
var loc = loc.split("/");
|
||||
loc = loc.slice(0, loc.length - 1).join("/");
|
||||
try {
|
||||
if (typeof WorkerGlobalScope === 'undefined' || !(self instanceof WorkerGlobalScope)) {
|
||||
//Use the catch block:
|
||||
throw null;
|
||||
}
|
||||
//Firefox:
|
||||
var loc2 = loc + "/graphics/Worker.js";
|
||||
this.worker = new Worker(loc2);
|
||||
}
|
||||
catch (e) {
|
||||
//Google Chrome:
|
||||
var loc3 = loc + "/IodineGBA/core/graphics/Worker.js";
|
||||
this.worker = new Worker(loc3);
|
||||
}
|
||||
this.worker.postMessage({
|
||||
messageID:1,
|
||||
skippingBIOS:!!skippingBIOS
|
||||
});
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.initializeBuffers = function () {
|
||||
//Graphics Buffers:
|
||||
this.gfxCommandBufferLength = 0x80000;
|
||||
this.gfxCommandBufferMask = ((this.gfxCommandBufferLength | 0) - 1) | 0;
|
||||
this.gfxCommandBuffer = getSharedInt32Array(this.gfxCommandBufferLength | 0);
|
||||
this.gfxCommandCounters = getSharedInt32Array(3);
|
||||
this.gfxLineCounter = getSharedInt32Array(1);
|
||||
this.start = 0;
|
||||
this.end = 0;
|
||||
this.linesPassed = 0;
|
||||
this.OAMRAM = getUint8Array(0x400);
|
||||
this.OAMRAM16 = getUint16View(this.OAMRAM);
|
||||
this.OAMRAM32 = getInt32View(this.OAMRAM);
|
||||
this.paletteRAM = getUint8Array(0x400);
|
||||
this.VRAM = getUint8Array(0x18000);
|
||||
this.VRAM16 = getUint16View(this.VRAM);
|
||||
this.VRAM32 = getInt32View(this.VRAM);
|
||||
this.paletteRAM16 = getUint16View(this.paletteRAM);
|
||||
this.paletteRAM32 = getInt32View(this.paletteRAM);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.increaseCommandBufferCapacity = function () {
|
||||
//Tell the other thread to break for receiving the new buffer:
|
||||
Atomics.store(this.gfxCommandCounters, 2, 1);
|
||||
//Double the size to the next power of 2:
|
||||
this.gfxCommandBufferLength = this.gfxCommandBufferLength << 1;
|
||||
this.gfxCommandBufferMask = ((this.gfxCommandBufferLength | 0) - 1) | 0;
|
||||
this.gfxCommandBuffer = getSharedInt32Array(this.gfxCommandBufferLength | 0);
|
||||
this.gfxCommandCounters = getSharedInt32Array(3);
|
||||
this.start = 0;
|
||||
this.end = 0;
|
||||
//Share our new buffers:
|
||||
this.shareDynamicBuffers();
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.appendAtomicSync = function () {
|
||||
//Command buffer counters get synchronized with emulator runtime head/end for efficiency:
|
||||
var parentObj = this;
|
||||
this.coreExposed.appendStartIterationSync(function () {
|
||||
parentObj.synchronizeReader();
|
||||
});
|
||||
this.coreExposed.appendEndIterationSync(function () {
|
||||
parentObj.synchronizeWriter();
|
||||
});
|
||||
this.coreExposed.appendTerminationSync(function () {
|
||||
//Core instance being replaced, kill the worker thread:
|
||||
parentObj.worker.terminate();
|
||||
});
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.shareStaticBuffers = function () {
|
||||
try {
|
||||
this.worker.postMessage({
|
||||
messageID:0,
|
||||
gfxBuffers:gfxBuffers,
|
||||
gfxCounters:gfxCounters,
|
||||
gfxLineCounter:this.gfxLineCounter
|
||||
}, [
|
||||
gfxBuffers[0].buffer,
|
||||
gfxBuffers[1].buffer,
|
||||
gfxCounters.buffer,
|
||||
this.gfxLineCounter.buffer
|
||||
]);
|
||||
}
|
||||
catch (e) {
|
||||
this.worker.postMessage({
|
||||
messageID:0,
|
||||
gfxBuffers:gfxBuffers,
|
||||
gfxCounters:gfxCounters,
|
||||
gfxLineCounter:this.gfxLineCounter
|
||||
});
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.shareDynamicBuffers = function () {
|
||||
try {
|
||||
this.worker.postMessage({
|
||||
messageID:2,
|
||||
gfxCommandBuffer:this.gfxCommandBuffer,
|
||||
gfxCommandCounters:this.gfxCommandCounters
|
||||
}, [
|
||||
this.gfxCommandBuffer.buffer,
|
||||
this.gfxCommandCounters.buffer
|
||||
]);
|
||||
}
|
||||
catch (e) {
|
||||
this.worker.postMessage({
|
||||
messageID:2,
|
||||
gfxCommandBuffer:this.gfxCommandBuffer,
|
||||
gfxCommandCounters:this.gfxCommandCounters
|
||||
});
|
||||
}
|
||||
//Wake up the producer "GPU" thread:
|
||||
Atomics.notify(gfxCounters, 2, 1);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.pushCommand = function (command, data) {
|
||||
command = command | 0;
|
||||
data = data | 0;
|
||||
//Check if buffer is full:
|
||||
this.checkCommandBufferFull();
|
||||
//Get the write offset into the ring buffer:
|
||||
var endCorrected = this.end & this.gfxCommandBufferMask;
|
||||
//Push command into buffer:
|
||||
this.gfxCommandBuffer[endCorrected | 0] = command | 0;
|
||||
//Push data into buffer:
|
||||
this.gfxCommandBuffer[endCorrected | 1] = data | 0;
|
||||
//Update the cross thread buffering count:
|
||||
this.end = ((this.end | 0) + 2) | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.checkCommandBufferFull = function () {
|
||||
if ((this.start | 0) == (((this.end | 0) - (this.gfxCommandBufferLength | 0)) | 0)) {
|
||||
//Give the reader our updated counter and tell it to run:
|
||||
this.synchronizeWriter();
|
||||
//Increase buffer size:
|
||||
this.increaseCommandBufferCapacity();
|
||||
//Reload reader counter value:
|
||||
this.synchronizeReader();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.synchronizeWriter = function () {
|
||||
//Store command buffer writer counter value:
|
||||
Atomics.store(this.gfxCommandCounters, 1, this.end | 0);
|
||||
Atomics.store(this.gfxLineCounter, 0, this.linesPassed | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.synchronizeReader = function () {
|
||||
//Load command buffer reader counter value:
|
||||
this.start = Atomics.load(this.gfxCommandCounters, 0) | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.pushVRAM16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
address = address & 0xFFFF;
|
||||
this.pushCommand(0x10000 | address, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.pushVRAM32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
address = address & 0x7FFF;
|
||||
this.pushCommand(0x20000 | address, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.pushPAL16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
address = address & 0x1FF;
|
||||
this.pushCommand(0x30000 | address, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.pushPAL32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
address = address & 0xFF;
|
||||
this.pushCommand(0x40000 | address, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.pushOAM16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
address = address & 0x1FF;
|
||||
this.pushCommand(0x50000 | address, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.pushOAM32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
address = address & 0xFF;
|
||||
this.pushCommand(0x60000 | address, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.incrementScanLineQueue = function () {
|
||||
//Increment scan line command:
|
||||
this.pushCommand(0, 0);
|
||||
//Increment how many scanlines we've pushed out:
|
||||
this.linesPassed = ((this.linesPassed | 0) + 1) | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.ensureFraming = function () {
|
||||
//Vertical blank synchronization command:
|
||||
this.pushCommand(0, 1);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeDISPCNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(1, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeDISPCNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(2, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeDISPCNT8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(3, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeDISPCNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(4, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeDISPCNT32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(5, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0CNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(6, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0CNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(7, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0CNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(8, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1CNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(9, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1CNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(10, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1CNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(11, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0BG1CNT32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(12, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2CNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(13, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2CNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(14, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2CNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(15, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3CNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(16, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3CNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(17, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3CNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(18, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2BG3CNT32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(19, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0HOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(20, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0HOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(21, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0HOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(22, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0VOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(23, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0VOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(24, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0VOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(25, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG0OFS32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(26, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1HOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(27, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1HOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(28, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1HOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(29, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1VOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(30, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1VOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(31, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1VOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(32, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG1OFS32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(33, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2HOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(34, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2HOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(35, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2HOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(36, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2VOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(37, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2VOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(38, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2VOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(39, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2OFS32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(40, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3HOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(41, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3HOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(42, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3HOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(43, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3VOFS8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(44, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3VOFS8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(45, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3VOFS16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(46, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3OFS32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(47, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PA8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(48, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PA8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(49, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PA16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(50, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PB8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(51, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PB8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(52, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PB16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(53, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PAB32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(54, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PC8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(55, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PC8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(56, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PC16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(57, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PD8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(58, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PD8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(59, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PD16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(60, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2PCD32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(61, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PA8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(62, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PA8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(63, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PA16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(64, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PB8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(65, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PB8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(66, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PB16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(67, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PAB32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(68, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PC8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(69, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PC8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(70, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PC16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(71, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PD8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(72, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PD8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(73, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PD16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(74, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3PCD32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(75, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2X8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(76, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2X8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(77, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2X8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(78, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2X8_3 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(79, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2X16_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(80, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2X16_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(81, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2X32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(82, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2Y8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(83, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2Y8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(84, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2Y8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(85, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2Y8_3 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(86, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2Y16_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(87, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2Y16_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(88, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG2Y32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(89, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3X8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(90, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3X8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(91, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3X8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(92, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3X8_3 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(93, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3X16_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(94, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3X16_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(95, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3X32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(96, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3Y8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(97, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3Y8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(98, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3Y8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(99, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3Y8_3 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(100, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3Y16_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(101, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3Y16_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(102, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBG3Y32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(103, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN0XCOORDRight8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(104, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN0XCOORDLeft8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(105, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN0XCOORD16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(106, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN1XCOORDRight8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(107, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN1XCOORDLeft8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(108, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN1XCOORD16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(109, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWINXCOORD32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(110, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN0YCOORDBottom8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(111, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN0YCOORDTop8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(112, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN0YCOORD16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(113, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN1YCOORDBottom8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(114, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN1YCOORDTop8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(115, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN1YCOORD16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(116, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWINYCOORD32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(117, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN0IN8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(118, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWIN1IN8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(119, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWININ16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(120, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWINOUT8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(121, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWINOBJIN8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(122, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWINOUT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(123, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeWINCONTROL32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(124, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeMOSAIC8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(125, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeMOSAIC8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(126, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeMOSAIC16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(127, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBLDCNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(128, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBLDCNT8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(129, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBLDCNT16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(130, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBLDALPHA8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(131, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBLDALPHA8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(132, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBLDALPHA16 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(133, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBLDCNT32 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(134, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeBLDY8 = function (data) {
|
||||
data = data | 0;
|
||||
this.pushCommand(135, data | 0);
|
||||
}
|
||||
if (__LITTLE_ENDIAN__) {
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeVRAM8 =
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeVRAM16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
this.VRAM16[address & 0xFFFF] = data & 0xFFFF;
|
||||
this.pushVRAM16(address | 0, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeVRAM32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
this.VRAM32[address & 0x7FFF] = data | 0;
|
||||
this.pushVRAM32(address | 0, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readVRAM16 = function (address) {
|
||||
address = address | 0;
|
||||
return this.VRAM16[address & 0xFFFF] | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readVRAM32 = function (address) {
|
||||
address = address | 0;
|
||||
return this.VRAM32[address & 0x7FFF] | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writePalette16 = function (address, data) {
|
||||
data = data | 0;
|
||||
address = address | 0;
|
||||
this.paletteRAM16[address & 0x1FF] = data & 0xFFFF;
|
||||
this.pushPAL16(address | 0, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writePalette32 = function (address, data) {
|
||||
data = data | 0;
|
||||
address = address | 0;
|
||||
this.paletteRAM32[address & 0xFF] = data | 0;
|
||||
this.pushPAL32(address | 0, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readPalette16 = function (address) {
|
||||
address = address | 0;
|
||||
return this.paletteRAM16[address & 0x1FF] | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readPalette32 = function (address) {
|
||||
address = address | 0;
|
||||
return this.paletteRAM32[address & 0xFF] | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeOAM16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
this.OAMRAM16[address & 0x1FF] = data & 0xFFFF;
|
||||
this.pushOAM16(address | 0, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeOAM32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
this.OAMRAM32[address & 0xFF] = data | 0;
|
||||
this.pushOAM32(address | 0, data | 0);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readOAM16 = function (address) {
|
||||
address = address | 0;
|
||||
return this.OAMRAM16[address & 0x1FF] | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readOAM32 = function (address) {
|
||||
address = address | 0;
|
||||
return this.OAMRAM32[address & 0xFF] | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeVRAM8 =
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeVRAM16 = function (address, data) {
|
||||
address <<= 1;
|
||||
address &= 0x1FFFE;
|
||||
this.VRAM[address] = data & 0xFF;
|
||||
this.VRAM[address + 1] = (data >> 8) & 0xFF;
|
||||
this.pushVRAM16(address, data);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeVRAM32 = function (address, data) {
|
||||
address <<= 2;
|
||||
address &= 0x1FFFC;
|
||||
this.VRAM[address] = data & 0xFF;
|
||||
this.VRAM[address + 1] = (data >> 8) & 0xFF;
|
||||
this.VRAM[address + 2] = (data >> 16) & 0xFF;
|
||||
this.VRAM[address + 3] = data >>> 24;
|
||||
this.pushVRAM32(address, data);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readVRAM16 = function (address) {
|
||||
address <<= 1;
|
||||
address &= 0x1FFFE;
|
||||
return this.VRAM[address] | (this.VRAM[address + 1] << 8);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readVRAM32 = function (address) {
|
||||
address <<= 2;
|
||||
address &= 0x1FFFC;
|
||||
return this.VRAM[address] | (this.VRAM[address + 1] << 8) | (this.VRAM[address + 2] << 16) | (this.VRAM[address + 3] << 24);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writePalette16 = function (address, data) {
|
||||
this.paletteRAM[address << 1] = data & 0xFF;
|
||||
this.paletteRAM[(address << 1) + 1] = data >> 8;
|
||||
this.pushPAL16(address, data);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writePalette32 = function (address, data) {
|
||||
address <<= 2;
|
||||
this.paletteRAM[address] = data & 0xFF;
|
||||
this.paletteRAM[address | 1] = (data >> 8) & 0xFF;
|
||||
this.paletteRAM[address | 2] = (data >> 16) & 0xFF;
|
||||
this.paletteRAM[address | 3] = data >>> 24;
|
||||
address >>= 2;
|
||||
this.pushPAL32(address, data);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readPalette16 = function (address) {
|
||||
address &= 0x3FE;
|
||||
return this.paletteRAM[address] | (this.paletteRAM[address | 1] << 8);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readPalette32 = function (address) {
|
||||
address &= 0x3FC;
|
||||
return this.paletteRAM[address] | (this.paletteRAM[address | 1] << 8) | (this.paletteRAM[address | 2] << 16) | (this.paletteRAM[address | 3] << 24);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeOAM16 = function (address, data) {
|
||||
address &= 0x1FF;
|
||||
this.OAMRAM[address << 1] = data & 0xFF;
|
||||
this.OAMRAM[(address << 1) | 1] = data >> 8;
|
||||
this.pushOAM16(address, data);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.writeOAM32 = function (address, data) {
|
||||
address &= 0xFF;
|
||||
address <<= 2;
|
||||
this.OAMRAM[address] = data & 0xFF;
|
||||
this.OAMRAM[address + 1] = (data >> 8) & 0xFF;
|
||||
this.OAMRAM[address + 2] = (data >> 16) & 0xFF;
|
||||
this.OAMRAM[address + 3] = data >>> 24;
|
||||
address >>= 2;
|
||||
this.pushOAM32(address, data);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readOAM16 = function (address) {
|
||||
address &= 0x1FF;
|
||||
address <<= 1;
|
||||
return this.OAMRAM[address] | (this.OAMRAM[address | 1] << 8);
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readOAM32 = function (address) {
|
||||
address &= 0xFF;
|
||||
address <<= 2;
|
||||
return this.OAMRAM[address] | (this.OAMRAM[address | 1] << 8) | (this.OAMRAM[address | 2] << 16) | (this.OAMRAM[address | 3] << 24);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readVRAM8 = function (address) {
|
||||
address = address | 0;
|
||||
return this.VRAM[address & 0x1FFFF] | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readOAM = function (address) {
|
||||
address = address | 0;
|
||||
return this.OAMRAM[address & 0x3FF] | 0;
|
||||
}
|
||||
GameBoyAdvanceGraphicsRendererShim.prototype.readPalette8 = function (address) {
|
||||
address = address | 0;
|
||||
return this.paletteRAM[address & 0x3FF] | 0;
|
||||
}
|
116
public/gfiles/gba/IodineGBA/core/graphics/Window.js
Normal file
116
public/gfiles/gba/IodineGBA/core/graphics/Window.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceWindowRenderer(compositor) {
|
||||
//Get a layer compositor that we'll send our parameters for windowing to:
|
||||
this.compositor = compositor;
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.initialize = function () {
|
||||
//Initialize the compositor:
|
||||
this.compositor.initialize();
|
||||
//Right windowing coordinate:
|
||||
this.WINXCoordRight = 0;
|
||||
//Left windowing coordinate:
|
||||
this.WINXCoordLeft = 0;
|
||||
//Bottom windowing coordinate:
|
||||
this.WINYCoordBottom = 0;
|
||||
//Top windowing coordinate:
|
||||
this.WINYCoordTop = 0;
|
||||
//Layer masking & color effects control:
|
||||
this.windowDisplayControl = 0;
|
||||
//Need to update the color effects status in the compositor:
|
||||
this.preprocess();
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.renderScanLine = function (line, toRender) {
|
||||
line = line | 0;
|
||||
toRender = toRender | 0;
|
||||
//Windowing can disable out further layers:
|
||||
toRender = toRender & this.windowDisplayControl;
|
||||
//Check if we're doing windowing for the current line:
|
||||
if (this.checkYRange(line | 0)) {
|
||||
//Windowing is active for the current line:
|
||||
var right = this.WINXCoordRight | 0;
|
||||
var left = this.WINXCoordLeft | 0;
|
||||
if ((left | 0) <= (right | 0)) {
|
||||
//Windowing is left to right like expected:
|
||||
left = Math.min(left | 0, 240) | 0;
|
||||
right = Math.min(right | 0, 240) | 0;
|
||||
//Render left coordinate to right coordinate:
|
||||
this.compositor.renderScanLine(left | 0, right | 0, toRender | 0);
|
||||
}
|
||||
else {
|
||||
//Invalid horizontal windowing coordinates, so invert horizontal windowing range:
|
||||
left = Math.min(left | 0, 240) | 0;
|
||||
right = Math.min(right | 0, 240) | 0;
|
||||
//Render pixel 0 to right coordinate:
|
||||
this.compositor.renderScanLine(0, right | 0, toRender | 0);
|
||||
//Render left coordinate to last pixel:
|
||||
this.compositor.renderScanLine(left | 0, 240, toRender | 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.checkYRange = function (line) {
|
||||
line = line | 0;
|
||||
var bottom = this.WINYCoordBottom | 0;
|
||||
var top = this.WINYCoordTop | 0;
|
||||
if ((top | 0) <= (bottom | 0)) {
|
||||
//Windowing is top to bottom like expected:
|
||||
return ((line | 0) >= (top | 0) && (line | 0) < (bottom | 0));
|
||||
}
|
||||
else {
|
||||
//Invalid vertical windowing coordinates, so invert vertical windowing range:
|
||||
return ((line | 0) < (top | 0) || (line | 0) >= (bottom | 0));
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.preprocess = function () {
|
||||
//Update the color effects status in the compositor:
|
||||
this.compositor.preprocess(this.windowDisplayControl & 0x20);
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.writeWINXCOORDRight8 = function (data) {
|
||||
data = data | 0;
|
||||
//Right windowing coordinate:
|
||||
this.WINXCoordRight = data | 0;
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.writeWINXCOORDLeft8 = function (data) {
|
||||
data = data | 0;
|
||||
//Left windowing coordinate:
|
||||
this.WINXCoordLeft = data | 0;
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.writeWINYCOORDBottom8 = function (data) {
|
||||
data = data | 0;
|
||||
//Bottom windowing coordinate:
|
||||
this.WINYCoordBottom = data | 0;
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.writeWINYCOORDTop8 = function (data) {
|
||||
data = data | 0;
|
||||
//Top windowing coordinate:
|
||||
this.WINYCoordTop = data | 0;
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.writeWINXCOORD16 = function (data) {
|
||||
data = data | 0;
|
||||
//Right windowing coordinate:
|
||||
this.WINXCoordRight = data & 0xFF;
|
||||
//Left windowing coordinate:
|
||||
this.WINXCoordLeft = data >> 8;
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.writeWINYCOORD16 = function (data) {
|
||||
data = data | 0;
|
||||
//Bottom windowing coordinate:
|
||||
this.WINYCoordBottom = data & 0xFF;
|
||||
//Top windowing coordinate:
|
||||
this.WINYCoordTop = data >> 8;
|
||||
}
|
||||
GameBoyAdvanceWindowRenderer.prototype.writeWININ8 = function (data) {
|
||||
data = data | 0;
|
||||
//Layer masking & color effects control:
|
||||
this.windowDisplayControl = data | 0;
|
||||
//Need to update the color effects status in the compositor:
|
||||
this.preprocess();
|
||||
}
|
587
public/gfiles/gba/IodineGBA/core/graphics/Worker.js
Normal file
587
public/gfiles/gba/IodineGBA/core/graphics/Worker.js
Normal file
|
@ -0,0 +1,587 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
importScripts("../../includes/TypedArrayShim.js");
|
||||
importScripts("Renderer.js");
|
||||
importScripts("BGTEXT.js");
|
||||
importScripts("BG2FrameBuffer.js");
|
||||
importScripts("BGMatrix.js");
|
||||
importScripts("AffineBG.js");
|
||||
importScripts("ColorEffects.js");
|
||||
importScripts("Mosaic.js");
|
||||
importScripts("OBJ.js");
|
||||
importScripts("OBJWindow.js");
|
||||
importScripts("Window.js");
|
||||
importScripts("Compositor.js");
|
||||
var renderer = null;
|
||||
var gfxBuffers = null;
|
||||
var gfxCounters = null;
|
||||
var gfxCommandBuffer = null;
|
||||
var gfxCommandCounters = null;
|
||||
var gfxCommandBufferMask = 1;
|
||||
var gfxLineCounter = null;
|
||||
var gfxLinesCPU = 0;
|
||||
var gfxLinesGPU = 0;
|
||||
self.onmessage = function (event) {
|
||||
var data = event.data;
|
||||
switch (data.messageID | 0) {
|
||||
case 0:
|
||||
assignStaticBuffers(data.gfxBuffers, data.gfxCounters, data.gfxLineCounter);
|
||||
break;
|
||||
case 1:
|
||||
initializeRenderer(!!data.skippingBIOS);
|
||||
break;
|
||||
default:
|
||||
assignDynamicBuffers(data.gfxCommandBuffer, data.gfxCommandCounters);
|
||||
waitForVSync();
|
||||
}
|
||||
}
|
||||
function copyBuffer(swizzledFrame) {
|
||||
//Push a frame of graphics to the blitter handle:
|
||||
//Load the counter values:
|
||||
var start = Atomics.load(gfxCounters, 0) | 0; //Written by the other thread.
|
||||
var end = gfxCounters[1] | 0; //Written by this thread.
|
||||
//Check if buffer is full:
|
||||
if ((end | 0) == (((start | 0) + 2) | 0)) {
|
||||
//Skip copying a frame out:
|
||||
return;
|
||||
}
|
||||
//Copy samples into the ring buffer:
|
||||
//Hardcoded for 2 buffers for a triple buffer effect:
|
||||
gfxBuffers[end & 0x1].set(swizzledFrame);
|
||||
//Increment the ending position counter by 1:
|
||||
//Atomic to commit the counter to memory:
|
||||
Atomics.store(gfxCounters, 1, ((end | 0) + 1) | 0);
|
||||
}
|
||||
function waitForVSync() {
|
||||
//Only breaks if the buffer gets resized:
|
||||
while ((Atomics.load(gfxCommandCounters, 2) | 0) == 0) {
|
||||
//Process the current buffer:
|
||||
processCommands();
|
||||
//Main thread calls wake to unblock us here:
|
||||
Atomics.wait(gfxCounters, 2, 0);
|
||||
}
|
||||
//Empty old buffer before getting a new buffer to refer to:
|
||||
processCommands();
|
||||
}
|
||||
function initializeRenderer(skippingBIOS) {
|
||||
skippingBIOS = !!skippingBIOS;
|
||||
renderer = new GameBoyAdvanceGraphicsRendererOffthread(!!skippingBIOS);
|
||||
}
|
||||
function assignStaticBuffers(gfxb, gfxc, cmdl) {
|
||||
gfxBuffers = gfxb;
|
||||
gfxCounters = gfxc;
|
||||
gfxLineCounter = cmdl;
|
||||
}
|
||||
function assignDynamicBuffers(cmdb, cmdc) {
|
||||
gfxCommandBuffer = cmdb;
|
||||
gfxCommandCounters = cmdc;
|
||||
var gfxCommandBufferLength = gfxCommandBuffer.length | 0;
|
||||
gfxCommandBufferMask = ((gfxCommandBufferLength | 0) - 1) | 0;
|
||||
}
|
||||
function processCommands() {
|
||||
//Load the counter values:
|
||||
var start = gfxCommandCounters[0] | 0; //Written by this thread.
|
||||
var end = Atomics.load(gfxCommandCounters, 1) | 0; //Written by the other thread.
|
||||
gfxLinesCPU = Atomics.load(gfxLineCounter, 0) | 0; //Keep atomic; IonMonkey thinks this is dead code if it's removed.
|
||||
//Don't process if nothing to process:
|
||||
if ((end | 0) == (start | 0)) {
|
||||
//Buffer is empty:
|
||||
return;
|
||||
}
|
||||
//Dispatch commands:
|
||||
var startCorrected = start & gfxCommandBufferMask;
|
||||
var endCorrected = end & gfxCommandBufferMask;
|
||||
do {
|
||||
//Read a command:
|
||||
dispatchCommand(gfxCommandBuffer[startCorrected | 0] | 0, gfxCommandBuffer[startCorrected | 1] | 0);
|
||||
//Increment by two since we're reading the command code and corresponding data after it:
|
||||
startCorrected = ((startCorrected | 0) + 2) & gfxCommandBufferMask;
|
||||
} while ((startCorrected | 0) != (endCorrected | 0));
|
||||
//Update the starting position counter to match the end position:
|
||||
Atomics.store(gfxCommandCounters, 0, end | 0);
|
||||
}
|
||||
function dispatchCommand(command, data) {
|
||||
command = command | 0;
|
||||
data = data | 0;
|
||||
/*
|
||||
We squeeze some address bits as a portion of the command code.
|
||||
The top bits will be the actual command, the bottom ones will be the address,
|
||||
unless of course the top bits are zero, for which then it's purely a command code:
|
||||
*/
|
||||
switch (command >> 16) {
|
||||
//IO:
|
||||
case 0:
|
||||
dispatchIOCommand(command | 0, data | 0);
|
||||
break;
|
||||
//VRAM 16-BIT:
|
||||
case 1:
|
||||
renderer.writeVRAM16(command & 0xFFFF, data | 0);
|
||||
break;
|
||||
//VRAM 32-BIT:
|
||||
case 2:
|
||||
renderer.writeVRAM32(command & 0x7FFF, data | 0);
|
||||
break;
|
||||
//Palette 16-BIT:
|
||||
case 3:
|
||||
renderer.writePalette16(command & 0x1FF, data | 0);
|
||||
break;
|
||||
//Palette 32-BIT:
|
||||
case 4:
|
||||
renderer.writePalette32(command & 0xFF, data | 0);
|
||||
break;
|
||||
//OAM 16-BIT:
|
||||
case 5:
|
||||
renderer.writeOAM16(command & 0x1FF, data | 0);
|
||||
break;
|
||||
//OAM 32-BIT:
|
||||
default:
|
||||
renderer.writeOAM32(command & 0xFF, data | 0);
|
||||
}
|
||||
}
|
||||
function dispatchIOCommand(command, data) {
|
||||
command = command | 0;
|
||||
data = data | 0;
|
||||
switch (command | 0) {
|
||||
case 0:
|
||||
decodeInternalCommand(data | 0);
|
||||
break;
|
||||
case 1:
|
||||
renderer.writeDISPCNT8_0(data | 0);
|
||||
break;
|
||||
case 2:
|
||||
renderer.writeDISPCNT8_1(data | 0);
|
||||
break;
|
||||
case 3:
|
||||
renderer.writeDISPCNT8_2(data | 0);
|
||||
break;
|
||||
case 4:
|
||||
renderer.writeDISPCNT16(data | 0);
|
||||
break;
|
||||
case 5:
|
||||
renderer.writeDISPCNT32(data | 0);
|
||||
break;
|
||||
case 6:
|
||||
renderer.writeBG0CNT8_0(data | 0);
|
||||
break;
|
||||
case 7:
|
||||
renderer.writeBG0CNT8_1(data | 0);
|
||||
break;
|
||||
case 8:
|
||||
renderer.writeBG0CNT16(data | 0);
|
||||
break;
|
||||
case 9:
|
||||
renderer.writeBG1CNT8_0(data | 0);
|
||||
break;
|
||||
case 10:
|
||||
renderer.writeBG1CNT8_1(data | 0);
|
||||
break;
|
||||
case 11:
|
||||
renderer.writeBG1CNT16(data | 0);
|
||||
break;
|
||||
case 12:
|
||||
renderer.writeBG0BG1CNT32(data | 0);
|
||||
break;
|
||||
case 13:
|
||||
renderer.writeBG2CNT8_0(data | 0);
|
||||
break;
|
||||
case 14:
|
||||
renderer.writeBG2CNT8_1(data | 0);
|
||||
break;
|
||||
case 15:
|
||||
renderer.writeBG2CNT16(data | 0);
|
||||
break;
|
||||
case 16:
|
||||
renderer.writeBG3CNT8_0(data | 0);
|
||||
break;
|
||||
case 17:
|
||||
renderer.writeBG3CNT8_1(data | 0);
|
||||
break;
|
||||
case 18:
|
||||
renderer.writeBG3CNT16(data | 0);
|
||||
break;
|
||||
case 19:
|
||||
renderer.writeBG2BG3CNT32(data | 0);
|
||||
break;
|
||||
case 20:
|
||||
renderer.writeBG0HOFS8_0(data | 0);
|
||||
break;
|
||||
case 21:
|
||||
renderer.writeBG0HOFS8_1(data | 0);
|
||||
break;
|
||||
case 22:
|
||||
renderer.writeBG0HOFS16(data | 0);
|
||||
break;
|
||||
case 23:
|
||||
renderer.writeBG0VOFS8_0(data | 0);
|
||||
break;
|
||||
case 24:
|
||||
renderer.writeBG0VOFS8_1(data | 0);
|
||||
break;
|
||||
case 25:
|
||||
renderer.writeBG0VOFS16(data | 0);
|
||||
break;
|
||||
case 26:
|
||||
renderer.writeBG0OFS32(data | 0);
|
||||
break;
|
||||
case 27:
|
||||
renderer.writeBG1HOFS8_0(data | 0);
|
||||
break;
|
||||
case 28:
|
||||
renderer.writeBG1HOFS8_1(data | 0);
|
||||
break;
|
||||
case 29:
|
||||
renderer.writeBG1HOFS16(data | 0);
|
||||
break;
|
||||
case 30:
|
||||
renderer.writeBG1VOFS8_0(data | 0);
|
||||
break;
|
||||
case 31:
|
||||
renderer.writeBG1VOFS8_1(data | 0);
|
||||
break;
|
||||
case 32:
|
||||
renderer.writeBG1VOFS16(data | 0);
|
||||
break;
|
||||
case 33:
|
||||
renderer.writeBG1OFS32(data | 0);
|
||||
break;
|
||||
case 34:
|
||||
renderer.writeBG2HOFS8_0(data | 0);
|
||||
break;
|
||||
case 35:
|
||||
renderer.writeBG2HOFS8_1(data | 0);
|
||||
break;
|
||||
case 36:
|
||||
renderer.writeBG2HOFS16(data | 0);
|
||||
break;
|
||||
case 37:
|
||||
renderer.writeBG2VOFS8_0(data | 0);
|
||||
break;
|
||||
case 38:
|
||||
renderer.writeBG2VOFS8_1(data | 0);
|
||||
break;
|
||||
case 39:
|
||||
renderer.writeBG2VOFS16(data | 0);
|
||||
break;
|
||||
case 40:
|
||||
renderer.writeBG2OFS32(data | 0);
|
||||
break;
|
||||
case 41:
|
||||
renderer.writeBG3HOFS8_0(data | 0);
|
||||
break;
|
||||
case 42:
|
||||
renderer.writeBG3HOFS8_1(data | 0);
|
||||
break;
|
||||
case 43:
|
||||
renderer.writeBG3HOFS16(data | 0);
|
||||
break;
|
||||
case 44:
|
||||
renderer.writeBG3VOFS8_0(data | 0);
|
||||
break;
|
||||
case 45:
|
||||
renderer.writeBG3VOFS8_1(data | 0);
|
||||
break;
|
||||
case 46:
|
||||
renderer.writeBG3VOFS16(data | 0);
|
||||
break;
|
||||
case 47:
|
||||
renderer.writeBG3OFS32(data | 0);
|
||||
break;
|
||||
case 48:
|
||||
renderer.writeBG2PA8_0(data | 0);
|
||||
break;
|
||||
case 49:
|
||||
renderer.writeBG2PA8_1(data | 0);
|
||||
break;
|
||||
case 50:
|
||||
renderer.writeBG2PA16(data | 0);
|
||||
break;
|
||||
case 51:
|
||||
renderer.writeBG2PB8_0(data | 0);
|
||||
break;
|
||||
case 52:
|
||||
renderer.writeBG2PB8_1(data | 0);
|
||||
break;
|
||||
case 53:
|
||||
renderer.writeBG2PB16(data | 0);
|
||||
break;
|
||||
case 54:
|
||||
renderer.writeBG2PAB32(data | 0);
|
||||
break;
|
||||
case 55:
|
||||
renderer.writeBG2PC8_0(data | 0);
|
||||
break;
|
||||
case 56:
|
||||
renderer.writeBG2PC8_1(data | 0);
|
||||
break;
|
||||
case 57:
|
||||
renderer.writeBG2PC16(data | 0);
|
||||
break;
|
||||
case 58:
|
||||
renderer.writeBG2PD8_0(data | 0);
|
||||
break;
|
||||
case 59:
|
||||
renderer.writeBG2PD8_1(data | 0);
|
||||
break;
|
||||
case 60:
|
||||
renderer.writeBG2PD16(data | 0);
|
||||
break;
|
||||
case 61:
|
||||
renderer.writeBG2PCD32(data | 0);
|
||||
break;
|
||||
case 62:
|
||||
renderer.writeBG3PA8_0(data | 0);
|
||||
break;
|
||||
case 63:
|
||||
renderer.writeBG3PA8_1(data | 0);
|
||||
break;
|
||||
case 64:
|
||||
renderer.writeBG3PA16(data | 0);
|
||||
break;
|
||||
case 65:
|
||||
renderer.writeBG3PB8_0(data | 0);
|
||||
break;
|
||||
case 66:
|
||||
renderer.writeBG3PB8_1(data | 0);
|
||||
break;
|
||||
case 67:
|
||||
renderer.writeBG3PB16(data | 0);
|
||||
break;
|
||||
case 68:
|
||||
renderer.writeBG3PAB32(data | 0);
|
||||
break;
|
||||
case 69:
|
||||
renderer.writeBG3PC8_0(data | 0);
|
||||
break;
|
||||
case 70:
|
||||
renderer.writeBG3PC8_1(data | 0);
|
||||
break;
|
||||
case 71:
|
||||
renderer.writeBG3PC16(data | 0);
|
||||
break;
|
||||
case 72:
|
||||
renderer.writeBG3PD8_0(data | 0);
|
||||
break;
|
||||
case 73:
|
||||
renderer.writeBG3PD8_1(data | 0);
|
||||
break;
|
||||
case 74:
|
||||
renderer.writeBG3PD16(data | 0);
|
||||
break;
|
||||
case 75:
|
||||
renderer.writeBG3PCD32(data | 0);
|
||||
break;
|
||||
case 76:
|
||||
renderer.writeBG2X8_0(data | 0);
|
||||
break;
|
||||
case 77:
|
||||
renderer.writeBG2X8_1(data | 0);
|
||||
break;
|
||||
case 78:
|
||||
renderer.writeBG2X8_2(data | 0);
|
||||
break;
|
||||
case 79:
|
||||
renderer.writeBG2X8_3(data | 0);
|
||||
break;
|
||||
case 80:
|
||||
renderer.writeBG2X16_0(data | 0);
|
||||
break;
|
||||
case 81:
|
||||
renderer.writeBG2X16_1(data | 0);
|
||||
break;
|
||||
case 82:
|
||||
renderer.writeBG2X32(data | 0);
|
||||
break;
|
||||
case 83:
|
||||
renderer.writeBG2Y8_0(data | 0);
|
||||
break;
|
||||
case 84:
|
||||
renderer.writeBG2Y8_1(data | 0);
|
||||
break;
|
||||
case 85:
|
||||
renderer.writeBG2Y8_2(data | 0);
|
||||
break;
|
||||
case 86:
|
||||
renderer.writeBG2Y8_3(data | 0);
|
||||
break;
|
||||
case 87:
|
||||
renderer.writeBG2Y16_0(data | 0);
|
||||
break;
|
||||
case 88:
|
||||
renderer.writeBG2Y16_1(data | 0);
|
||||
break;
|
||||
case 89:
|
||||
renderer.writeBG2Y32(data | 0);
|
||||
break;
|
||||
case 90:
|
||||
renderer.writeBG3X8_0(data | 0);
|
||||
break;
|
||||
case 91:
|
||||
renderer.writeBG3X8_1(data | 0);
|
||||
break;
|
||||
case 92:
|
||||
renderer.writeBG3X8_2(data | 0);
|
||||
break;
|
||||
case 93:
|
||||
renderer.writeBG3X8_3(data | 0);
|
||||
break;
|
||||
case 94:
|
||||
renderer.writeBG3X16_0(data | 0);
|
||||
break;
|
||||
case 95:
|
||||
renderer.writeBG3X16_1(data | 0);
|
||||
break;
|
||||
case 96:
|
||||
renderer.writeBG3X32(data | 0);
|
||||
break;
|
||||
case 97:
|
||||
renderer.writeBG3Y8_0(data | 0);
|
||||
break;
|
||||
case 98:
|
||||
renderer.writeBG3Y8_1(data | 0);
|
||||
break;
|
||||
case 99:
|
||||
renderer.writeBG3Y8_2(data | 0);
|
||||
break;
|
||||
case 100:
|
||||
renderer.writeBG3Y8_3(data | 0);
|
||||
break;
|
||||
case 101:
|
||||
renderer.writeBG3Y16_0(data | 0);
|
||||
break;
|
||||
case 102:
|
||||
renderer.writeBG3Y16_1(data | 0);
|
||||
break;
|
||||
case 103:
|
||||
renderer.writeBG3Y32(data | 0);
|
||||
break;
|
||||
case 104:
|
||||
renderer.writeWIN0XCOORDRight8(data | 0);
|
||||
break;
|
||||
case 105:
|
||||
renderer.writeWIN0XCOORDLeft8(data | 0);
|
||||
break;
|
||||
case 106:
|
||||
renderer.writeWIN0XCOORD16(data | 0);
|
||||
break;
|
||||
case 107:
|
||||
renderer.writeWIN1XCOORDRight8(data | 0);
|
||||
break;
|
||||
case 108:
|
||||
renderer.writeWIN1XCOORDLeft8(data | 0);
|
||||
break;
|
||||
case 109:
|
||||
renderer.writeWIN1XCOORD16(data | 0);
|
||||
break;
|
||||
case 110:
|
||||
renderer.writeWINXCOORD32(data | 0);
|
||||
break;
|
||||
case 111:
|
||||
renderer.writeWIN0YCOORDBottom8(data | 0);
|
||||
break;
|
||||
case 112:
|
||||
renderer.writeWIN0YCOORDTop8(data | 0);
|
||||
break;
|
||||
case 113:
|
||||
renderer.writeWIN0YCOORD16(data | 0);
|
||||
break;
|
||||
case 114:
|
||||
renderer.writeWIN1YCOORDBottom8(data | 0);
|
||||
break;
|
||||
case 115:
|
||||
renderer.writeWIN1YCOORDTop8(data | 0);
|
||||
break;
|
||||
case 116:
|
||||
renderer.writeWIN1YCOORD16(data | 0);
|
||||
break;
|
||||
case 117:
|
||||
renderer.writeWINYCOORD32(data | 0);
|
||||
break;
|
||||
case 118:
|
||||
renderer.writeWIN0IN8(data | 0);
|
||||
break;
|
||||
case 119:
|
||||
renderer.writeWIN1IN8(data | 0);
|
||||
break;
|
||||
case 120:
|
||||
renderer.writeWININ16(data | 0);
|
||||
break;
|
||||
case 121:
|
||||
renderer.writeWINOUT8(data | 0);
|
||||
break;
|
||||
case 122:
|
||||
renderer.writeWINOBJIN8(data | 0);
|
||||
break;
|
||||
case 123:
|
||||
renderer.writeWINOUT16(data | 0);
|
||||
break;
|
||||
case 124:
|
||||
renderer.writeWINCONTROL32(data | 0);
|
||||
break;
|
||||
case 125:
|
||||
renderer.writeMOSAIC8_0(data | 0);
|
||||
break;
|
||||
case 126:
|
||||
renderer.writeMOSAIC8_1(data | 0);
|
||||
break;
|
||||
case 127:
|
||||
renderer.writeMOSAIC16(data | 0);
|
||||
break;
|
||||
case 128:
|
||||
renderer.writeBLDCNT8_0(data | 0);
|
||||
break;
|
||||
case 129:
|
||||
renderer.writeBLDCNT8_1(data | 0);
|
||||
break;
|
||||
case 130:
|
||||
renderer.writeBLDCNT16(data | 0);
|
||||
break;
|
||||
case 131:
|
||||
renderer.writeBLDALPHA8_0(data | 0);
|
||||
break;
|
||||
case 132:
|
||||
renderer.writeBLDALPHA8_1(data | 0);
|
||||
break;
|
||||
case 133:
|
||||
renderer.writeBLDALPHA16(data | 0);
|
||||
break;
|
||||
case 134:
|
||||
renderer.writeBLDCNT32(data | 0);
|
||||
break;
|
||||
default:
|
||||
renderer.writeBLDY8(data | 0);
|
||||
}
|
||||
}
|
||||
function decodeInternalCommand(data) {
|
||||
data = data | 0;
|
||||
switch (data | 0) {
|
||||
case 0:
|
||||
//Check to see if we need to skip rendering to catch up:
|
||||
if ((((gfxLinesCPU | 0) - (gfxLinesGPU | 0)) | 0) < 480) {
|
||||
//Render a scanline:
|
||||
renderer.renderScanLine();
|
||||
}
|
||||
else {
|
||||
//Update some internal counters to maintain state:
|
||||
renderer.updateReferenceCounters();
|
||||
}
|
||||
//Clock the scanline counter:
|
||||
renderer.incrementScanLine();
|
||||
//Increment how many scanlines we've received out:
|
||||
gfxLinesGPU = ((gfxLinesGPU | 0) + 1) | 0;
|
||||
break;
|
||||
default:
|
||||
//Check to see if we need to skip rendering to catch up:
|
||||
if ((((gfxLinesCPU | 0) - (gfxLinesGPU | 0)) | 0) < 480) {
|
||||
//Push out a frame of graphics:
|
||||
renderer.prepareFrame();
|
||||
}
|
||||
}
|
||||
}
|
401
public/gfiles/gba/IodineGBA/core/memory/DMA0.js
Normal file
401
public/gfiles/gba/IodineGBA/core/memory/DMA0.js
Normal file
|
@ -0,0 +1,401 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceDMA0(IOCore) {
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.DMA_ENABLE_TYPE = [ //DMA Channel 0 Mapping:
|
||||
0x1,
|
||||
0x2,
|
||||
0x4,
|
||||
0x40
|
||||
];
|
||||
GameBoyAdvanceDMA0.prototype.initialize = function () {
|
||||
this.enabled = 0;
|
||||
this.pending = 0;
|
||||
this.source = 0;
|
||||
this.sourceShadow = 0;
|
||||
this.destination = 0;
|
||||
this.destinationShadow = 0;
|
||||
this.wordCount = 0;
|
||||
this.wordCountShadow = 0;
|
||||
this.irqFlagging = 0;
|
||||
this.dmaType = 0;
|
||||
this.is32Bit = 0;
|
||||
this.repeat = 0;
|
||||
this.sourceControl = 0;
|
||||
this.destinationControl = 0;
|
||||
this.DMACore = this.IOCore.dma;
|
||||
this.memory = this.IOCore.memory;
|
||||
this.gfxState = this.IOCore.gfxState;
|
||||
this.irq = this.IOCore.irq;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.validateDMASource = function (address) {
|
||||
address = address | 0;
|
||||
if ((address | 0) >= 0x2000000) {
|
||||
if ((address | 0) <= 0x7FFFFFF || (address | 0) >= 0xE000000) {
|
||||
this.source = address | 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.validateDMADestination = function (address) {
|
||||
address = address | 0;
|
||||
if ((address | 0) <= 0x7FFFFFF) {
|
||||
this.destination = address | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMASource8_0 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFFF00;
|
||||
data = data & 0xFF;
|
||||
source = source | data;
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMASource8_1 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFF00FF;
|
||||
data = data & 0xFF;
|
||||
source = source | (data << 8);
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMASource8_2 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xF00FFFF;
|
||||
data = data & 0xFF;
|
||||
source = source | (data << 16);
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMASource8_3 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFFFF;
|
||||
data = data & 0xF;
|
||||
source = source | (data << 24);
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMASource16_0 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFF0000;
|
||||
data = data & 0xFFFF;
|
||||
source = source | data;
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMASource16_1 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFF;
|
||||
data = data & 0xFFF;
|
||||
source = source | (data << 16);
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMASource32 = function (data) {
|
||||
data = data | 0;
|
||||
var source = data & 0xFFFFFFF;
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMADestination8_0 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFFFF00;
|
||||
data = data & 0xFF;
|
||||
destination = destination | data;
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMADestination8_1 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFF00FF;
|
||||
data = data & 0xFF;
|
||||
destination = destination | (data << 8);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMADestination8_2 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xF00FFFF;
|
||||
data = data & 0xFF;
|
||||
destination = destination | (data << 16);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMADestination8_3 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFFFFF;
|
||||
data = data & 0xF;
|
||||
destination = destination | (data << 24);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMADestination16_0 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFF0000;
|
||||
data = data & 0xFFFF;
|
||||
destination = destination | data;
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMADestination16_1 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFFF;
|
||||
data = data & 0xFFF;
|
||||
destination = destination | (data << 16);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMADestination32 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = data & 0xFFFFFFF;
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMAWordCount8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = this.wordCount & 0x3F00;
|
||||
data = data & 0xFF;
|
||||
this.wordCount = this.wordCount | data;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMAWordCount8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = this.wordCount & 0xFF;
|
||||
data = data & 0x3F;
|
||||
this.wordCount = this.wordCount | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMAWordCount16 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = data & 0x3FFF;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMAControl8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.destinationControl = (data >> 5) & 0x3;
|
||||
this.sourceControl = this.sourceControl & 0x2;
|
||||
this.sourceControl = this.sourceControl | ((data >> 7) & 0x1);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMAControl8_1 = function (data) {
|
||||
data = data | 0;
|
||||
//Spill state machine clocks:
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.sourceControl = (this.sourceControl & 0x1) | ((data & 0x1) << 1);
|
||||
this.repeat = data & 0x2;
|
||||
this.is32Bit = data & 0x4;
|
||||
this.dmaType = (data >> 4) & 0x3;
|
||||
this.irqFlagging = data & 0x40;
|
||||
this.enableDMAChannel(data & 0x80);
|
||||
//Calculate next event:
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMAControl16 = function (data) {
|
||||
data = data | 0;
|
||||
//Spill state machine clocks:
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.destinationControl = (data >> 5) & 0x3;
|
||||
this.sourceControl = (data >> 7) & 0x3;
|
||||
this.repeat = (data >> 8) & 0x2;
|
||||
this.is32Bit = (data >> 8) & 0x4;
|
||||
this.dmaType = (data >> 12) & 0x3;
|
||||
this.irqFlagging = (data >> 8) & 0x40;
|
||||
this.enableDMAChannel(data & 0x8000);
|
||||
//Calculate next event:
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.writeDMAControl32 = function (data) {
|
||||
data = data | 0;
|
||||
this.writeDMAWordCount16(data | 0);
|
||||
this.writeDMAControl16(data >> 16);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.readDMAControl8_0 = function () {
|
||||
var data = this.destinationControl << 5;
|
||||
data = data | ((this.sourceControl & 0x1) << 7);
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.readDMAControl8_1 = function () {
|
||||
var data = this.sourceControl >> 1;
|
||||
data = data | this.repeat;
|
||||
data = data | this.is32Bit;
|
||||
data = data | (this.dmaType << 4);
|
||||
data = data | this.irqFlagging;
|
||||
if ((this.enabled | 0) != 0) {
|
||||
data = data | 0x80;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.readDMAControl16 = function () {
|
||||
var data = this.destinationControl << 5;
|
||||
data = data | (this.sourceControl << 7);
|
||||
data = data | (this.repeat << 8);
|
||||
data = data | (this.is32Bit << 8);
|
||||
data = data | (this.dmaType << 12);
|
||||
data = data | (this.irqFlagging << 8);
|
||||
if ((this.enabled | 0) != 0) {
|
||||
data = data | 0x8000;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.getMatchStatus = function () {
|
||||
return this.enabled & this.pending;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.requestDMA = function (DMAType) {
|
||||
DMAType = DMAType | 0;
|
||||
if ((this.enabled & DMAType) != 0) {
|
||||
this.pending = DMAType | 0;
|
||||
this.DMACore.update();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.enableDMAChannel = function (enabled) {
|
||||
enabled = enabled | 0;
|
||||
if ((enabled | 0) != 0) {
|
||||
//If DMA was previously disabled, reload control registers:
|
||||
if ((this.enabled | 0) == 0) {
|
||||
//Flag immediate DMA transfers for processing now:
|
||||
this.pending = 0x1;
|
||||
//Shadow copy the word count:
|
||||
this.wordCountShadow = this.wordCount | 0;
|
||||
//Shadow copy the source address:
|
||||
this.sourceShadow = this.source | 0;
|
||||
//Shadow copy the destination address:
|
||||
this.destinationShadow = this.destination | 0;
|
||||
}
|
||||
//DMA type changed:
|
||||
this.enabled = this.DMA_ENABLE_TYPE[this.dmaType | 0] | 0;
|
||||
this.pending = this.pending & this.enabled;
|
||||
}
|
||||
else {
|
||||
//DMA Disabled:
|
||||
this.enabled = 0;
|
||||
}
|
||||
//Run some DMA channel activity checks:
|
||||
this.DMACore.update();
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.handleDMACopy = function () {
|
||||
//Get the addesses:
|
||||
var source = this.sourceShadow | 0;
|
||||
var destination = this.destinationShadow | 0;
|
||||
//Transfer Data:
|
||||
if ((this.is32Bit | 0) == 4) {
|
||||
//32-bit Transfer:
|
||||
this.copy32(source | 0, destination | 0);
|
||||
}
|
||||
else {
|
||||
//16-bit Transfer:
|
||||
this.copy16(source | 0, destination | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.copy16 = function (source, destination) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
var data = this.memory.memoryReadDMA16(source | 0) | 0;
|
||||
this.memory.memoryWriteDMA16(destination | 0, data | 0);
|
||||
this.decrementWordCount(source | 0, destination | 0, 2);
|
||||
this.DMACore.updateFetch(data | (data << 16));
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.copy32 = function (source, destination) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
var data = this.memory.memoryReadDMA32(source | 0) | 0;
|
||||
this.memory.memoryWriteDMA32(destination | 0, data | 0);
|
||||
this.decrementWordCount(source | 0, destination | 0, 4);
|
||||
this.DMACore.updateFetch(data | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.decrementWordCount = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Decrement the word count:
|
||||
var wordCountShadow = ((this.wordCountShadow | 0) - 1) & 0x3FFF;
|
||||
if ((wordCountShadow | 0) == 0) {
|
||||
//DMA transfer ended, handle accordingly:
|
||||
wordCountShadow = this.finalizeDMA(source | 0, destination | 0, transferred | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Update addresses:
|
||||
this.incrementDMAAddresses(source | 0, destination | 0, transferred | 0);
|
||||
}
|
||||
//Save the new word count:
|
||||
this.wordCountShadow = wordCountShadow | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.finalizeDMA = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
var wordCountShadow = 0;
|
||||
//Reset pending requests:
|
||||
this.pending = 0;
|
||||
//Check Repeat Status:
|
||||
if ((this.repeat | 0) == 0 || (this.enabled | 0) == 0x1) {
|
||||
//Disable the enable bit:
|
||||
this.enabled = 0;
|
||||
}
|
||||
else {
|
||||
//Reload word count:
|
||||
wordCountShadow = this.wordCount | 0;
|
||||
}
|
||||
//Run the DMA channel checks:
|
||||
this.DMACore.update();
|
||||
//Check to see if we should flag for IRQ:
|
||||
this.checkIRQTrigger();
|
||||
//Update addresses:
|
||||
this.finalDMAAddresses(source | 0, destination | 0, transferred | 0);
|
||||
return wordCountShadow | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.checkIRQTrigger = function () {
|
||||
if ((this.irqFlagging | 0) != 0) {
|
||||
this.irq.requestIRQ(0x100);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.finalDMAAddresses = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.sourceShadow = ((source | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
//Update destination address:
|
||||
switch (this.destinationControl | 0) {
|
||||
case 0: //Increment
|
||||
this.destinationShadow = ((destination | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.destinationShadow = ((destination | 0) - (transferred | 0)) | 0;
|
||||
break;
|
||||
case 3: //Reload
|
||||
this.destinationShadow = this.destination | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.incrementDMAAddresses = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1:
|
||||
this.sourceShadow = ((source | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
//Update destination address:
|
||||
switch (this.destinationControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Increment
|
||||
this.destinationShadow = ((destination | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.destinationShadow = ((destination | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA0.prototype.nextEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
switch (this.enabled | 0) {
|
||||
//V_BLANK
|
||||
case 0x2:
|
||||
clocks = this.gfxState.nextVBlankEventTime() | 0;
|
||||
break;
|
||||
//H_BLANK:
|
||||
case 0x4:
|
||||
clocks = this.gfxState.nextHBlankDMAEventTime() | 0;
|
||||
}
|
||||
return clocks | 0;
|
||||
}
|
473
public/gfiles/gba/IodineGBA/core/memory/DMA1.js
Normal file
473
public/gfiles/gba/IodineGBA/core/memory/DMA1.js
Normal file
|
@ -0,0 +1,473 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceDMA1(IOCore) {
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.DMA_ENABLE_TYPE = [ //DMA Channel 1 Mapping:
|
||||
0x1,
|
||||
0x2,
|
||||
0x4,
|
||||
0x8
|
||||
];
|
||||
GameBoyAdvanceDMA1.prototype.initialize = function () {
|
||||
this.enabled = 0;
|
||||
this.pending = 0;
|
||||
this.source = 0;
|
||||
this.sourceShadow = 0;
|
||||
this.destination = 0;
|
||||
this.destinationShadow = 0;
|
||||
this.wordCount = 0;
|
||||
this.wordCountShadow = 0;
|
||||
this.irqFlagging = 0;
|
||||
this.dmaType = 0;
|
||||
this.is32Bit = 0;
|
||||
this.repeat = 0;
|
||||
this.sourceControl = 0;
|
||||
this.destinationControl = 0;
|
||||
this.DMACore = this.IOCore.dma;
|
||||
this.memory = this.IOCore.memory;
|
||||
this.gfxState = this.IOCore.gfxState;
|
||||
this.irq = this.IOCore.irq;
|
||||
this.sound = this.IOCore.sound;
|
||||
this.wait = this.IOCore.wait;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.validateDMASource = function (address) {
|
||||
address = address | 0;
|
||||
if ((address | 0) >= 0x2000000) {
|
||||
this.source = address | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.validateDMADestination = function (address) {
|
||||
address = address | 0;
|
||||
if ((address | 0) <= 0x7FFFFFF) {
|
||||
this.destination = address | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMASource8_0 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFFF00;
|
||||
data = data & 0xFF;
|
||||
source = source | data;
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMASource8_1 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFF00FF;
|
||||
data = data & 0xFF;
|
||||
source = source | (data << 8);
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMASource8_2 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xF00FFFF;
|
||||
data = data & 0xFF;
|
||||
source = ource | (data << 16);
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMASource8_3 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFFFF;
|
||||
data = data & 0xF;
|
||||
source = source | (data << 24);
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMASource16_0 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFF0000;
|
||||
data = data & 0xFFFF;
|
||||
source = source | data;
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMASource16_1 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFF;
|
||||
data = data & 0xFFF;
|
||||
source = source | (data << 16);
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMASource32 = function (data) {
|
||||
data = data | 0;
|
||||
var source = data & 0xFFFFFFF;
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMADestination8_0 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFFFF00;
|
||||
data = data & 0xFF;
|
||||
destination = destination | data;
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMADestination8_1 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFF00FF;
|
||||
data = data & 0xFF;
|
||||
destination = destination | (data << 8);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMADestination8_2 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xF00FFFF;
|
||||
data = data & 0xFF;
|
||||
destination = destination | (data << 16);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMADestination8_3 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFFFFF;
|
||||
data = data & 0xF;
|
||||
destination = destination | (data << 24);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMADestination16_0 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFF0000;
|
||||
data = data & 0xFFFF;
|
||||
destination = destination | data;
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMADestination16_1 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFFF;
|
||||
data = data & 0xFFF;
|
||||
destination = destination | (data << 16);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMADestination32 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = data & 0xFFFFFFF;
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMAWordCount8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = this.wordCount & 0x3F00;
|
||||
data = data & 0xFF;
|
||||
this.wordCount = this.wordCount | data;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMAWordCount8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = this.wordCount & 0xFF;
|
||||
data = data & 0x3F;
|
||||
this.wordCount = this.wordCount | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMAWordCount16 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = data & 0x3FFF;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMAControl8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.destinationControl = (data >> 5) & 0x3;
|
||||
this.sourceControl = this.sourceControl & 0x2;
|
||||
this.sourceControl = this.sourceControl | ((data >> 7) & 0x1);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMAControl8_1 = function (data) {
|
||||
data = data | 0;
|
||||
//Spill state machine clocks:
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.sourceControl = (this.sourceControl & 0x1) | ((data & 0x1) << 1);
|
||||
this.repeat = data & 0x2;
|
||||
this.is32Bit = data & 0x4;
|
||||
this.dmaType = (data >> 4) & 0x3;
|
||||
this.irqFlagging = data & 0x40;
|
||||
this.enableDMAChannel(data & 0x80);
|
||||
//Calculate next event:
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMAControl16 = function (data) {
|
||||
data = data | 0;
|
||||
//Spill state machine clocks:
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.destinationControl = (data >> 5) & 0x3;
|
||||
this.sourceControl = (data >> 7) & 0x3;
|
||||
this.repeat = (data >> 8) & 0x2;
|
||||
this.is32Bit = (data >> 8) & 0x4;
|
||||
this.dmaType = (data >> 12) & 0x3;
|
||||
this.irqFlagging = (data >> 8) & 0x40;
|
||||
this.enableDMAChannel(data & 0x8000);
|
||||
//Calculate next event:
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.writeDMAControl32 = function (data) {
|
||||
data = data | 0;
|
||||
this.writeDMAWordCount16(data | 0);
|
||||
this.writeDMAControl16(data >> 16);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.readDMAControl8_0 = function () {
|
||||
var data = this.destinationControl << 5;
|
||||
data = data | ((this.sourceControl & 0x1) << 7);
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.readDMAControl8_1 = function () {
|
||||
var data = this.sourceControl >> 1;
|
||||
data = data | this.repeat;
|
||||
data = data | this.is32Bit;
|
||||
data = data | (this.dmaType << 4);
|
||||
data = data | this.irqFlagging;
|
||||
if ((this.enabled | 0) != 0) {
|
||||
data = data | 0x80;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.readDMAControl16 = function () {
|
||||
var data = this.destinationControl << 5;
|
||||
data = data | (this.sourceControl << 7);
|
||||
data = data | (this.repeat << 8);
|
||||
data = data | (this.is32Bit << 8);
|
||||
data = data | (this.dmaType << 12);
|
||||
data = data | (this.irqFlagging << 8);
|
||||
if ((this.enabled | 0) != 0) {
|
||||
data = data | 0x8000;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.getMatchStatus = function () {
|
||||
return this.enabled & this.pending;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.soundFIFOARequest = function () {
|
||||
this.requestDMA(0x8);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.requestDMA = function (DMAType) {
|
||||
DMAType = DMAType | 0;
|
||||
if ((this.enabled & DMAType) != 0) {
|
||||
this.pending = DMAType | 0;
|
||||
this.DMACore.update();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.enableDMAChannel = function (enabled) {
|
||||
enabled = enabled | 0;
|
||||
if ((enabled | 0) != 0) {
|
||||
//If DMA was previously disabled, reload control registers:
|
||||
if ((this.enabled | 0) == 0) {
|
||||
switch (this.dmaType | 0) {
|
||||
case 0x3:
|
||||
//Direct Sound DMA Hardwired To Wordcount Of 4:
|
||||
this.wordCountShadow = 0x4;
|
||||
break;
|
||||
case 0:
|
||||
//Flag immediate DMA transfers for processing now:
|
||||
this.pending = 0x1;
|
||||
default:
|
||||
//Shadow copy the word count:
|
||||
this.wordCountShadow = this.wordCount | 0;
|
||||
|
||||
}
|
||||
//Shadow copy the source address:
|
||||
this.sourceShadow = this.source | 0;
|
||||
//Shadow copy the destination address:
|
||||
this.destinationShadow = this.destination | 0;
|
||||
}
|
||||
//DMA type changed:
|
||||
this.enabled = this.DMA_ENABLE_TYPE[this.dmaType | 0] | 0;
|
||||
this.pending = this.pending & this.enabled;
|
||||
//Assert the FIFO A DMA request signal:
|
||||
this.sound.checkFIFOAPendingSignal();
|
||||
}
|
||||
else {
|
||||
//DMA Disabled:
|
||||
this.enabled = 0;
|
||||
}
|
||||
//Run some DMA channel activity checks:
|
||||
this.DMACore.update();
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.handleDMACopy = function () {
|
||||
//Get the source addess:
|
||||
var source = this.sourceShadow | 0;
|
||||
//Transfer Data:
|
||||
if ((this.enabled | 0) == 0x8) {
|
||||
//32-bit Transfer:
|
||||
this.copySound(source | 0);
|
||||
}
|
||||
else {
|
||||
//Get the destination address:
|
||||
var destination = this.destinationShadow | 0;
|
||||
if ((this.is32Bit | 0) == 4) {
|
||||
//32-bit Transfer:
|
||||
this.copy32(source | 0, destination | 0);
|
||||
}
|
||||
else {
|
||||
//16-bit Transfer:
|
||||
this.copy16(source | 0, destination | 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.copy16 = function (source, destination) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
var data = this.memory.memoryReadDMAFull16(source | 0) | 0;
|
||||
this.memory.memoryWriteDMA16(destination | 0, data | 0);
|
||||
this.decrementWordCount(source | 0, destination | 0, 2);
|
||||
this.DMACore.updateFetch(data | (data << 16));
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.copy32 = function (source, destination) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
var data = this.memory.memoryReadDMAFull32(source | 0) | 0;
|
||||
this.memory.memoryWriteDMA32(destination | 0, data | 0);
|
||||
this.decrementWordCount(source | 0, destination | 0, 4);
|
||||
this.DMACore.updateFetch(data | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.copySound = function (source) {
|
||||
source = source | 0;
|
||||
var data = this.memory.memoryReadDMAFull32(source | 0) | 0;
|
||||
this.wait.singleClock();
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.sound.writeFIFOA32(data | 0);
|
||||
this.soundDMAUpdate(source | 0);
|
||||
this.DMACore.updateFetch(data | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.decrementWordCount = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Decrement the word count:
|
||||
var wordCountShadow = ((this.wordCountShadow | 0) - 1) & 0x3FFF;
|
||||
if ((wordCountShadow | 0) == 0) {
|
||||
//DMA transfer ended, handle accordingly:
|
||||
wordCountShadow = this.finalizeDMA(source | 0, destination | 0, transferred | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Update addresses:
|
||||
this.incrementDMAAddresses(source | 0, destination | 0, transferred | 0);
|
||||
}
|
||||
//Save the new word count:
|
||||
this.wordCountShadow = wordCountShadow | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.soundDMAUpdate = function (source) {
|
||||
source = source | 0;
|
||||
//Decrement the word count:
|
||||
this.wordCountShadow = ((this.wordCountShadow | 0) - 1) & 0x3FFF;
|
||||
if ((this.wordCountShadow | 0) == 0) {
|
||||
//DMA transfer ended, handle accordingly:
|
||||
//Reset pending requests:
|
||||
this.pending = 0;
|
||||
//Check Repeat Status:
|
||||
if ((this.repeat | 0) == 0) {
|
||||
//Disable the enable bit:
|
||||
this.enabled = 0;
|
||||
}
|
||||
else {
|
||||
//Repeating the dma:
|
||||
//Direct Sound DMA Hardwired To Wordcount Of 4:
|
||||
this.wordCountShadow = 0x4;
|
||||
}
|
||||
//Assert the FIFO A DMA request signal:
|
||||
this.sound.checkFIFOAPendingSignal();
|
||||
//Run the DMA channel checks:
|
||||
this.DMACore.update();
|
||||
//Check to see if we should flag for IRQ:
|
||||
this.checkIRQTrigger();
|
||||
}
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + 4) | 0;
|
||||
break;
|
||||
case 1:
|
||||
this.sourceShadow = ((source | 0) - 4) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.finalizeDMA = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
var wordCountShadow = 0;
|
||||
//Reset pending requests:
|
||||
this.pending = 0;
|
||||
//Check Repeat Status:
|
||||
if ((this.repeat | 0) == 0 || (this.enabled | 0) == 0x1) {
|
||||
//Disable the enable bit:
|
||||
this.enabled = 0;
|
||||
}
|
||||
else {
|
||||
//Repeating the dma:
|
||||
//Reload word count:
|
||||
wordCountShadow = this.wordCount | 0;
|
||||
}
|
||||
//Assert the FIFO A DMA request signal:
|
||||
this.sound.checkFIFOAPendingSignal();
|
||||
//Run the DMA channel checks:
|
||||
this.DMACore.update();
|
||||
//Check to see if we should flag for IRQ:
|
||||
this.checkIRQTrigger();
|
||||
//Update addresses:
|
||||
this.finalDMAAddresses(source | 0, destination | 0, transferred | 0);
|
||||
return wordCountShadow | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.checkIRQTrigger = function () {
|
||||
if ((this.irqFlagging | 0) != 0) {
|
||||
this.irq.requestIRQ(0x200);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.finalDMAAddresses = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.sourceShadow = ((source | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
//Update destination address:
|
||||
switch (this.destinationControl | 0) {
|
||||
case 0: //Increment
|
||||
this.destinationShadow = ((destination | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.destinationShadow = ((destination | 0) - (transferred | 0)) | 0;
|
||||
break;
|
||||
case 3: //Reload
|
||||
this.destinationShadow = this.destination | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.incrementDMAAddresses = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1:
|
||||
this.sourceShadow = ((source | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
//Update destination address:
|
||||
switch (this.destinationControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Increment
|
||||
this.destinationShadow = ((destination | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.destinationShadow = ((destination | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA1.prototype.nextEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
switch (this.enabled | 0) {
|
||||
//V_BLANK
|
||||
case 0x2:
|
||||
clocks = this.gfxState.nextVBlankEventTime() | 0;
|
||||
break;
|
||||
//H_BLANK:
|
||||
case 0x4:
|
||||
clocks = this.gfxState.nextHBlankDMAEventTime() | 0;
|
||||
break;
|
||||
//FIFO_A:
|
||||
case 0x8:
|
||||
clocks = this.sound.nextFIFOAEventTime() | 0;
|
||||
}
|
||||
return clocks | 0;
|
||||
}
|
472
public/gfiles/gba/IodineGBA/core/memory/DMA2.js
Normal file
472
public/gfiles/gba/IodineGBA/core/memory/DMA2.js
Normal file
|
@ -0,0 +1,472 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceDMA2(IOCore) {
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.DMA_ENABLE_TYPE = [ //DMA Channel 2 Mapping:
|
||||
0x1,
|
||||
0x2,
|
||||
0x4,
|
||||
0x10
|
||||
];
|
||||
GameBoyAdvanceDMA2.prototype.initialize = function () {
|
||||
this.enabled = 0;
|
||||
this.pending = 0;
|
||||
this.source = 0;
|
||||
this.sourceShadow = 0;
|
||||
this.destination = 0;
|
||||
this.destinationShadow = 0;
|
||||
this.wordCount = 0;
|
||||
this.wordCountShadow = 0;
|
||||
this.irqFlagging = 0;
|
||||
this.dmaType = 0;
|
||||
this.is32Bit = 0;
|
||||
this.repeat = 0;
|
||||
this.sourceControl = 0;
|
||||
this.destinationControl = 0;
|
||||
this.DMACore = this.IOCore.dma;
|
||||
this.memory = this.IOCore.memory;
|
||||
this.gfxState = this.IOCore.gfxState;
|
||||
this.irq = this.IOCore.irq;
|
||||
this.sound = this.IOCore.sound;
|
||||
this.wait = this.IOCore.wait;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.validateDMASource = function (address) {
|
||||
address = address | 0;
|
||||
if ((address | 0) >= 0x2000000) {
|
||||
this.source = address | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.validateDMADestination = function (address) {
|
||||
address = address | 0;
|
||||
if ((address | 0) <= 0x7FFFFFF) {
|
||||
this.destination = address | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMASource8_0 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFFF00;
|
||||
data = data & 0xFF;
|
||||
source = source | data;
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMASource8_1 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFF00FF;
|
||||
data = data & 0xFF;
|
||||
source = source | (data << 8);
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMASource8_2 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xF00FFFF;
|
||||
data = data & 0xFF;
|
||||
source = ource | (data << 16);
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMASource8_3 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFFFF;
|
||||
data = data & 0xF;
|
||||
source = source | (data << 24);
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMASource16_0 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFF0000;
|
||||
data = data & 0xFFFF;
|
||||
source = source | data;
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMASource16_1 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFF;
|
||||
data = data & 0xFFF;
|
||||
source = source | (data << 16);
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMASource32 = function (data) {
|
||||
data = data | 0;
|
||||
var source = data & 0xFFFFFFF;
|
||||
this.validateDMASource(source | 0)
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMADestination8_0 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFFFF00;
|
||||
data = data & 0xFF;
|
||||
destination = destination | data;
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMADestination8_1 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFF00FF;
|
||||
data = data & 0xFF;
|
||||
destination = destination | (data << 8);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMADestination8_2 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xF00FFFF;
|
||||
data = data & 0xFF;
|
||||
destination = destination | (data << 16);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMADestination8_3 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFFFFF;
|
||||
data = data & 0xF;
|
||||
destination = destination | (data << 24);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMADestination16_0 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFF0000;
|
||||
data = data & 0xFFFF;
|
||||
destination = destination | data;
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMADestination16_1 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = this.destination & 0xFFFF;
|
||||
data = data & 0xFFF;
|
||||
destination = destination | (data << 16);
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMADestination32 = function (data) {
|
||||
data = data | 0;
|
||||
var destination = data & 0xFFFFFFF;
|
||||
this.validateDMADestination(destination | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMAWordCount8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = this.wordCount & 0x3F00;
|
||||
data = data & 0xFF;
|
||||
this.wordCount = this.wordCount | data;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMAWordCount8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = this.wordCount & 0xFF;
|
||||
data = data & 0x3F;
|
||||
this.wordCount = this.wordCount | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMAWordCount16 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = data & 0x3FFF;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMAControl8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.destinationControl = (data >> 5) & 0x3;
|
||||
this.sourceControl = this.sourceControl & 0x2;
|
||||
this.sourceControl = this.sourceControl | ((data >> 7) & 0x1);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMAControl8_1 = function (data) {
|
||||
data = data | 0;
|
||||
//Spill state machine clocks:
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.sourceControl = (this.sourceControl & 0x1) | ((data & 0x1) << 1);
|
||||
this.repeat = data & 0x2;
|
||||
this.is32Bit = data & 0x4;
|
||||
this.dmaType = (data >> 4) & 0x3;
|
||||
this.irqFlagging = data & 0x40;
|
||||
this.enableDMAChannel(data & 0x80);
|
||||
//Calculate next event:
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMAControl16 = function (data) {
|
||||
data = data | 0;
|
||||
//Spill state machine clocks:
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.destinationControl = (data >> 5) & 0x3;
|
||||
this.sourceControl = (data >> 7) & 0x3;
|
||||
this.repeat = (data >> 8) & 0x2;
|
||||
this.is32Bit = (data >> 8) & 0x4;
|
||||
this.dmaType = (data >> 12) & 0x3;
|
||||
this.irqFlagging = (data >> 8) & 0x40;
|
||||
this.enableDMAChannel(data & 0x8000);
|
||||
//Calculate next event:
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.writeDMAControl32 = function (data) {
|
||||
data = data | 0;
|
||||
this.writeDMAWordCount16(data | 0);
|
||||
this.writeDMAControl16(data >> 16);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.readDMAControl8_0 = function () {
|
||||
var data = this.destinationControl << 5;
|
||||
data = data | ((this.sourceControl & 0x1) << 7);
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.readDMAControl8_1 = function () {
|
||||
var data = this.sourceControl >> 1;
|
||||
data = data | this.repeat;
|
||||
data = data | this.is32Bit;
|
||||
data = data | (this.dmaType << 4);
|
||||
data = data | this.irqFlagging;
|
||||
if ((this.enabled | 0) != 0) {
|
||||
data = data | 0x80;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.readDMAControl16 = function () {
|
||||
var data = this.destinationControl << 5;
|
||||
data = data | (this.sourceControl << 7);
|
||||
data = data | (this.repeat << 8);
|
||||
data = data | (this.is32Bit << 8);
|
||||
data = data | (this.dmaType << 12);
|
||||
data = data | (this.irqFlagging << 8);
|
||||
if ((this.enabled | 0) != 0) {
|
||||
data = data | 0x8000;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.getMatchStatus = function () {
|
||||
return this.enabled & this.pending;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.soundFIFOBRequest = function () {
|
||||
this.requestDMA(0x10);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.requestDMA = function (DMAType) {
|
||||
DMAType = DMAType | 0;
|
||||
if ((this.enabled & DMAType) != 0) {
|
||||
this.pending = DMAType | 0;
|
||||
this.DMACore.update();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.enableDMAChannel = function (enabled) {
|
||||
enabled = enabled | 0;
|
||||
if ((enabled | 0) != 0) {
|
||||
//If DMA was previously disabled, reload control registers:
|
||||
if ((this.enabled | 0) == 0) {
|
||||
switch (this.dmaType | 0) {
|
||||
case 0x3:
|
||||
//Direct Sound DMA Hardwired To Wordcount Of 4:
|
||||
this.wordCountShadow = 0x4;
|
||||
break;
|
||||
case 0:
|
||||
//Flag immediate DMA transfers for processing now:
|
||||
this.pending = 0x1;
|
||||
default:
|
||||
//Shadow copy the word count:
|
||||
this.wordCountShadow = this.wordCount | 0;
|
||||
}
|
||||
//Shadow copy the source address:
|
||||
this.sourceShadow = this.source | 0;
|
||||
//Shadow copy the destination address:
|
||||
this.destinationShadow = this.destination | 0;
|
||||
}
|
||||
//DMA type changed:
|
||||
this.enabled = this.DMA_ENABLE_TYPE[this.dmaType | 0] | 0;
|
||||
//this.pending = this.pending & this.enabled;
|
||||
//Assert the FIFO A DMA request signal:
|
||||
this.sound.checkFIFOBPendingSignal();
|
||||
}
|
||||
else {
|
||||
//DMA Disabled:
|
||||
this.enabled = 0;
|
||||
}
|
||||
//Run some DMA channel activity checks:
|
||||
this.DMACore.update();
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.handleDMACopy = function () {
|
||||
//Get the source addess:
|
||||
var source = this.sourceShadow | 0;
|
||||
//Transfer Data:
|
||||
if ((this.enabled | 0) == 0x10) {
|
||||
//32-bit Transfer:
|
||||
this.copySound(source | 0);
|
||||
}
|
||||
else {
|
||||
//Get the destination address:
|
||||
var destination = this.destinationShadow | 0;
|
||||
if ((this.is32Bit | 0) == 4) {
|
||||
//32-bit Transfer:
|
||||
this.copy32(source | 0, destination | 0);
|
||||
}
|
||||
else {
|
||||
//16-bit Transfer:
|
||||
this.copy16(source | 0, destination | 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.copy16 = function (source, destination) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
var data = this.memory.memoryReadDMAFull16(source | 0) | 0;
|
||||
this.memory.memoryWriteDMA16(destination | 0, data | 0);
|
||||
this.decrementWordCount(source | 0, destination | 0, 2);
|
||||
this.DMACore.updateFetch(data | (data << 16));
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.copy32 = function (source, destination) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
var data = this.memory.memoryReadDMAFull32(source | 0) | 0;
|
||||
this.memory.memoryWriteDMA32(destination | 0, data | 0);
|
||||
this.decrementWordCount(source | 0, destination | 0, 4);
|
||||
this.DMACore.updateFetch(data | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.copySound = function (source) {
|
||||
source = source | 0;
|
||||
var data = this.memory.memoryReadDMAFull32(source | 0) | 0;
|
||||
this.wait.singleClock();
|
||||
this.IOCore.updateTimerClocking();
|
||||
this.sound.writeFIFOB32(data | 0);
|
||||
this.soundDMAUpdate(source | 0);
|
||||
this.DMACore.updateFetch(data | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.decrementWordCount = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Decrement the word count:
|
||||
var wordCountShadow = ((this.wordCountShadow | 0) - 1) & 0x3FFF;
|
||||
if ((wordCountShadow | 0) == 0) {
|
||||
//DMA transfer ended, handle accordingly:
|
||||
wordCountShadow = this.finalizeDMA(source | 0, destination | 0, transferred | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Update addresses:
|
||||
this.incrementDMAAddresses(source | 0, destination | 0, transferred | 0);
|
||||
}
|
||||
//Save the new word count:
|
||||
this.wordCountShadow = wordCountShadow | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.soundDMAUpdate = function (source) {
|
||||
source = source | 0;
|
||||
//Decrement the word count:
|
||||
this.wordCountShadow = ((this.wordCountShadow | 0) - 1) & 0x3FFF;
|
||||
if ((this.wordCountShadow | 0) == 0) {
|
||||
//DMA transfer ended, handle accordingly:
|
||||
//Reset pending requests:
|
||||
this.pending = 0;
|
||||
//Check Repeat Status:
|
||||
if ((this.repeat | 0) == 0) {
|
||||
//Disable the enable bit:
|
||||
this.enabled = 0;
|
||||
}
|
||||
else {
|
||||
//Repeating the dma:
|
||||
//Direct Sound DMA Hardwired To Wordcount Of 4:
|
||||
this.wordCountShadow = 0x4;
|
||||
}
|
||||
//Assert the FIFO B DMA request signal:
|
||||
this.sound.checkFIFOBPendingSignal();
|
||||
//Run the DMA channel checks:
|
||||
this.DMACore.update();
|
||||
//Check to see if we should flag for IRQ:
|
||||
this.checkIRQTrigger();
|
||||
}
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + 4) | 0;
|
||||
break;
|
||||
case 1:
|
||||
this.sourceShadow = ((source | 0) - 4) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.finalizeDMA = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
var wordCountShadow = 0;
|
||||
//Reset pending requests:
|
||||
this.pending = 0;
|
||||
//Check Repeat Status:
|
||||
if ((this.repeat | 0) == 0 || (this.enabled | 0) == 0x1) {
|
||||
//Disable the enable bit:
|
||||
this.enabled = 0;
|
||||
}
|
||||
else {
|
||||
//Repeating the dma:
|
||||
//Reload word count:
|
||||
wordCountShadow = this.wordCount | 0;
|
||||
}
|
||||
//Assert the FIFO B DMA request signal:
|
||||
this.sound.checkFIFOBPendingSignal();
|
||||
//Run the DMA channel checks:
|
||||
this.DMACore.update();
|
||||
//Check to see if we should flag for IRQ:
|
||||
this.checkIRQTrigger();
|
||||
//Update addresses:
|
||||
this.finalDMAAddresses(source | 0, destination | 0, transferred | 0);
|
||||
return wordCountShadow | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.checkIRQTrigger = function () {
|
||||
if ((this.irqFlagging | 0) != 0) {
|
||||
this.irq.requestIRQ(0x400);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.finalDMAAddresses = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.sourceShadow = ((source | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
//Update destination address:
|
||||
switch (this.destinationControl | 0) {
|
||||
case 0: //Increment
|
||||
this.destinationShadow = ((destination | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.destinationShadow = ((destination | 0) - (transferred | 0)) | 0;
|
||||
break;
|
||||
case 3: //Reload
|
||||
this.destinationShadow = this.destination | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.incrementDMAAddresses = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1:
|
||||
this.sourceShadow = ((source | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
//Update destination address:
|
||||
switch (this.destinationControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Increment
|
||||
this.destinationShadow = ((destination | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.destinationShadow = ((destination | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA2.prototype.nextEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
switch (this.enabled | 0) {
|
||||
//V_BLANK
|
||||
case 0x2:
|
||||
clocks = this.gfxState.nextVBlankEventTime() | 0;
|
||||
break;
|
||||
//H_BLANK:
|
||||
case 0x4:
|
||||
clocks = this.gfxState.nextHBlankDMAEventTime() | 0;
|
||||
break;
|
||||
//FIFO_B:
|
||||
case 0x10:
|
||||
clocks = this.sound.nextFIFOBEventTime() | 0;
|
||||
}
|
||||
return clocks | 0;
|
||||
}
|
418
public/gfiles/gba/IodineGBA/core/memory/DMA3.js
Normal file
418
public/gfiles/gba/IodineGBA/core/memory/DMA3.js
Normal file
|
@ -0,0 +1,418 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceDMA3(IOCore) {
|
||||
this.IOCore = IOCore;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.DMA_ENABLE_TYPE = [ //DMA Channel 3 Mapping:
|
||||
0x1,
|
||||
0x2,
|
||||
0x4,
|
||||
0x20
|
||||
];
|
||||
GameBoyAdvanceDMA3.prototype.initialize = function () {
|
||||
this.enabled = 0;
|
||||
this.pending = 0;
|
||||
this.source = 0;
|
||||
this.sourceShadow = 0;
|
||||
this.destination = 0;
|
||||
this.destinationShadow = 0;
|
||||
this.wordCount = 0;
|
||||
this.wordCountShadow = 0;
|
||||
this.irqFlagging = 0;
|
||||
this.dmaType = 0;
|
||||
this.is32Bit = 0;
|
||||
this.repeat = 0;
|
||||
this.sourceControl = 0;
|
||||
this.destinationControl = 0;
|
||||
this.gamePakDMA = 0;
|
||||
this.displaySyncEnableDelay = 0;
|
||||
this.DMACore = this.IOCore.dma;
|
||||
this.memory = this.IOCore.memory;
|
||||
this.gfxState = this.IOCore.gfxState;
|
||||
this.irq = this.IOCore.irq;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.validateDMASource = function (address) {
|
||||
address = address | 0;
|
||||
if ((address | 0) >= 0x2000000) {
|
||||
this.source = address | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMASource8_0 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFFF00;
|
||||
data = data & 0xFF;
|
||||
source = source | data;
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMASource8_1 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFF00FF;
|
||||
data = data & 0xFF;
|
||||
source = source | (data << 8);
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMASource8_2 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xF00FFFF;
|
||||
data = data & 0xFF;
|
||||
source = source | (data << 16);
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMASource8_3 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFFFF;
|
||||
data = data & 0xF;
|
||||
source = source | (data << 24);
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMASource16_0 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFF0000;
|
||||
data = data & 0xFFFF;
|
||||
source = source | data;
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMASource16_1 = function (data) {
|
||||
data = data | 0;
|
||||
var source = this.source & 0xFFFF;
|
||||
data = data & 0xFFF;
|
||||
source = source | (data << 16);
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMASource32 = function (data) {
|
||||
data = data | 0;
|
||||
var source = data & 0xFFFFFFF;
|
||||
this.validateDMASource(source | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMADestination8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.destination = this.destination & 0xFFFFF00;
|
||||
data = data & 0xFF;
|
||||
this.destination = this.destination | data;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMADestination8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.destination = this.destination & 0xFFF00FF;
|
||||
data = data & 0xFF;
|
||||
this.destination = this.destination | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMADestination8_2 = function (data) {
|
||||
data = data | 0;
|
||||
this.destination = this.destination & 0xF00FFFF;
|
||||
data = data & 0xFF;
|
||||
this.destination = this.destination | (data << 16);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMADestination8_3 = function (data) {
|
||||
data = data | 0;
|
||||
this.destination = this.destination & 0xFFFFFF;
|
||||
data = data & 0xF;
|
||||
this.destination = this.destination | (data << 24);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMADestination16_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.destination = this.destination & 0xFFF0000;
|
||||
data = data & 0xFFFF;
|
||||
this.destination = this.destination | data;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMADestination16_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.destination = this.destination & 0xFFFF;
|
||||
data = data & 0xFFF;
|
||||
this.destination = this.destination | (data << 16);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMADestination32 = function (data) {
|
||||
data = data | 0;
|
||||
this.destination = data & 0xFFFFFFF;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMAWordCount8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = this.wordCount & 0xFF00;
|
||||
data = data & 0xFF;
|
||||
this.wordCount = this.wordCount | data;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMAWordCount8_1 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = this.wordCount & 0xFF;
|
||||
data = data & 0xFF;
|
||||
this.wordCount = this.wordCount | (data << 8);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMAWordCount16 = function (data) {
|
||||
data = data | 0;
|
||||
this.wordCount = data & 0xFFFF;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMAControl8_0 = function (data) {
|
||||
data = data | 0;
|
||||
this.destinationControl = (data >> 5) & 0x3;
|
||||
this.sourceControl = this.sourceControl & 0x2;
|
||||
this.sourceControl = this.sourceControl | ((data >> 7) & 0x1);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMAControl8_1 = function (data) {
|
||||
data = data | 0;
|
||||
//Spill state machine clocks:
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.sourceControl = (this.sourceControl & 0x1) | ((data & 0x1) << 1);
|
||||
this.repeat = data & 0x2;
|
||||
this.is32Bit = data & 0x4;
|
||||
this.gamePakDMA = data & 0x8;
|
||||
this.dmaType = (data >> 4) & 0x3;
|
||||
this.irqFlagging = data & 0x40;
|
||||
this.enableDMAChannel(data & 0x80);
|
||||
//Calculate next event:
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMAControl16 = function (data) {
|
||||
data = data | 0;
|
||||
//Spill state machine clocks:
|
||||
this.IOCore.updateCoreClocking();
|
||||
this.destinationControl = (data >> 5) & 0x3;
|
||||
this.sourceControl = (data >> 7) & 0x3;
|
||||
this.repeat = (data >> 8) & 0x2;
|
||||
this.is32Bit = (data >> 8) & 0x4;
|
||||
this.gamePakDMA = (data >> 8) & 0x8;
|
||||
this.dmaType = (data >> 12) & 0x3;
|
||||
this.irqFlagging = (data >> 8) & 0x40;
|
||||
this.enableDMAChannel(data & 0x8000);
|
||||
//Calculate next event:
|
||||
this.IOCore.updateCoreEventTime();
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.writeDMAControl32 = function (data) {
|
||||
data = data | 0;
|
||||
this.writeDMAWordCount16(data | 0);
|
||||
this.writeDMAControl16(data >> 16);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.readDMAControl8_0 = function () {
|
||||
var data = this.destinationControl << 5;
|
||||
data = data | ((this.sourceControl & 0x1) << 7);
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.readDMAControl8_1 = function () {
|
||||
var data = this.sourceControl >> 1;
|
||||
data = data | this.repeat;
|
||||
data = data | this.is32Bit;
|
||||
data = data | this.gamePakDMA;
|
||||
data = data | (this.dmaType << 4);
|
||||
data = data | this.irqFlagging;
|
||||
if ((this.enabled | 0) != 0) {
|
||||
data = data | 0x80;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.readDMAControl16 = function () {
|
||||
var data = this.destinationControl << 5;
|
||||
data = data | (this.sourceControl << 7);
|
||||
data = data | (this.repeat << 8);
|
||||
data = data | (this.is32Bit << 8);
|
||||
data = data | (this.gamePakDMA << 8);
|
||||
data = data | (this.dmaType << 12);
|
||||
data = data | (this.irqFlagging << 8);
|
||||
if ((this.enabled | 0) != 0) {
|
||||
data = data | 0x8000;
|
||||
}
|
||||
return data | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.getMatchStatus = function () {
|
||||
return this.enabled & this.pending;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.gfxDisplaySyncRequest = function () {
|
||||
this.requestDMA(0x20 ^ this.displaySyncEnableDelay);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.gfxDisplaySyncEnableCheck = function () {
|
||||
//Reset the display sync & reassert DMA enable line:
|
||||
if ((this.enabled | 0) == 0x20) {
|
||||
if ((this.displaySyncEnableDelay | 0) == 0x20) {
|
||||
this.displaySyncEnableDelay = 0;
|
||||
}
|
||||
else {
|
||||
this.enabled = 0;
|
||||
this.DMACore.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.requestDMA = function (DMAType) {
|
||||
DMAType = DMAType | 0;
|
||||
if ((this.enabled & DMAType) != 0) {
|
||||
this.pending = DMAType | 0;
|
||||
this.DMACore.update();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.enableDMAChannel = function (enabled) {
|
||||
enabled = enabled | 0;
|
||||
if ((enabled | 0) != 0) {
|
||||
//If DMA was previously disabled, reload control registers:
|
||||
if ((this.enabled | 0) == 0) {
|
||||
switch (this.dmaType | 0) {
|
||||
case 0:
|
||||
//Flag immediate DMA transfers for processing now:
|
||||
this.pending = 0x1;
|
||||
break;
|
||||
case 0x3:
|
||||
//Trigger display sync DMA shadow enable and auto-check on line 162:
|
||||
this.displaySyncEnableDelay = 0x20;
|
||||
}
|
||||
//Shadow copy the word count:
|
||||
this.wordCountShadow = this.wordCount | 0;
|
||||
//Shadow copy the source address:
|
||||
this.sourceShadow = this.source | 0;
|
||||
//Shadow copy the destination address:
|
||||
this.destinationShadow = this.destination | 0;
|
||||
}
|
||||
//DMA type changed:
|
||||
this.enabled = this.DMA_ENABLE_TYPE[this.dmaType | 0] | 0;
|
||||
this.pending = this.pending & this.enabled;
|
||||
}
|
||||
else {
|
||||
//DMA Disabled:
|
||||
this.enabled = 0;
|
||||
}
|
||||
//Run some DMA channel activity checks:
|
||||
this.DMACore.update();
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.handleDMACopy = function () {
|
||||
//Get the addesses:
|
||||
var source = this.sourceShadow | 0;
|
||||
var destination = this.destinationShadow | 0;
|
||||
//Transfer Data:
|
||||
if ((this.is32Bit | 0) == 4) {
|
||||
//32-bit Transfer:
|
||||
this.copy32(source | 0, destination | 0);
|
||||
}
|
||||
else {
|
||||
//16-bit Transfer:
|
||||
this.copy16(source | 0, destination | 0);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.copy16 = function (source, destination) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
var data = this.memory.memoryReadDMAFull16(source | 0) | 0;
|
||||
this.memory.memoryWriteDMAFull16(destination | 0, data | 0);
|
||||
this.decrementWordCount(source | 0, destination | 0, 2);
|
||||
this.DMACore.updateFetch(data | (data << 16));
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.copy32 = function (source, destination) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
var data = this.memory.memoryReadDMAFull32(source | 0) | 0;
|
||||
this.memory.memoryWriteDMAFull32(destination | 0, data | 0);
|
||||
this.decrementWordCount(source | 0, destination | 0, 4);
|
||||
this.DMACore.updateFetch(data | 0);
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.decrementWordCount = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Decrement the word count:
|
||||
var wordCountShadow = ((this.wordCountShadow | 0) - 1) & 0xFFFF;
|
||||
if ((wordCountShadow | 0) == 0) {
|
||||
//DMA transfer ended, handle accordingly:
|
||||
wordCountShadow = this.finalizeDMA(source | 0, destination | 0, transferred | 0) | 0;
|
||||
}
|
||||
else {
|
||||
//Update addresses:
|
||||
this.incrementDMAAddresses(source | 0, destination | 0, transferred | 0);
|
||||
}
|
||||
//Save the new word count:
|
||||
this.wordCountShadow = wordCountShadow | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.finalizeDMA = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
var wordCountShadow = 0;
|
||||
//Reset pending requests:
|
||||
this.pending = 0;
|
||||
//Check Repeat Status:
|
||||
if ((this.repeat | 0) == 0 || (this.enabled | 0) == 0x1) {
|
||||
//Disable the enable bit:
|
||||
this.enabled = 0;
|
||||
}
|
||||
else {
|
||||
//Reload word count:
|
||||
wordCountShadow = this.wordCount | 0;
|
||||
}
|
||||
//Run the DMA channel checks:
|
||||
this.DMACore.update();
|
||||
//Check to see if we should flag for IRQ:
|
||||
this.checkIRQTrigger();
|
||||
//Update addresses:
|
||||
this.finalDMAAddresses(source | 0, destination | 0, transferred | 0);
|
||||
return wordCountShadow | 0;
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.checkIRQTrigger = function () {
|
||||
if ((this.irqFlagging | 0) != 0) {
|
||||
this.irq.requestIRQ(0x800);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.finalDMAAddresses = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.sourceShadow = ((source | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
//Update destination address:
|
||||
switch (this.destinationControl | 0) {
|
||||
case 0: //Increment
|
||||
this.destinationShadow = ((destination | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.destinationShadow = ((destination | 0) - (transferred | 0)) | 0;
|
||||
break;
|
||||
case 3: //Reload
|
||||
this.destinationShadow = this.destination | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.incrementDMAAddresses = function (source, destination, transferred) {
|
||||
source = source | 0;
|
||||
destination = destination | 0;
|
||||
transferred = transferred | 0;
|
||||
//Update source address:
|
||||
switch (this.sourceControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Forbidden (VBA has it increment)
|
||||
this.sourceShadow = ((source | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1:
|
||||
this.sourceShadow = ((source | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
//Update destination address:
|
||||
switch (this.destinationControl | 0) {
|
||||
case 0: //Increment
|
||||
case 3: //Increment
|
||||
this.destinationShadow = ((destination | 0) + (transferred | 0)) | 0;
|
||||
break;
|
||||
case 1: //Decrement
|
||||
this.destinationShadow = ((destination | 0) - (transferred | 0)) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceDMA3.prototype.nextEventTime = function () {
|
||||
var clocks = 0x7FFFFFFF;
|
||||
switch (this.enabled | 0) {
|
||||
//V_BLANK
|
||||
case 0x2:
|
||||
clocks = this.gfxState.nextVBlankEventTime() | 0;
|
||||
break;
|
||||
//H_BLANK:
|
||||
case 0x4:
|
||||
clocks = this.gfxState.nextHBlankDMAEventTime() | 0;
|
||||
break;
|
||||
//DISPLAY_SYNC:
|
||||
case 0x20:
|
||||
clocks = this.gfxState.nextDisplaySyncEventTime(this.displaySyncEnableDelay | 0) | 0;
|
||||
}
|
||||
return clocks | 0;
|
||||
}
|
298
public/gfiles/gba/IodineGBA/core/sound/Channel1.js
Normal file
298
public/gfiles/gba/IodineGBA/core/sound/Channel1.js
Normal file
|
@ -0,0 +1,298 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceChannel1Synth(sound) {
|
||||
this.sound = sound;
|
||||
this.currentSampleLeft = 0;
|
||||
this.currentSampleRight = 0;
|
||||
this.SweepFault = false;
|
||||
this.lastTimeSweep = 0;
|
||||
this.timeSweep = 0;
|
||||
this.frequencySweepDivider = 0;
|
||||
this.decreaseSweep = false;
|
||||
this.nr11 = 0;
|
||||
this.CachedDuty = 0xF0000000;
|
||||
this.totalLength = 0x40;
|
||||
this.nr12 = 0;
|
||||
this.envelopeVolume = 0;
|
||||
this.frequency = 0;
|
||||
this.FrequencyTracker = 0x8000;
|
||||
this.nr14 = 0;
|
||||
this.consecutive = true;
|
||||
this.ShadowFrequency = 0x8000;
|
||||
this.canPlay = false;
|
||||
this.Enabled = 0;
|
||||
this.envelopeSweeps = 0;
|
||||
this.envelopeSweepsLast = -1;
|
||||
this.FrequencyCounter = 0;
|
||||
this.DutyTracker = 0;
|
||||
this.Swept = false;
|
||||
this.leftEnable = 0;
|
||||
this.rightEnable = 0;
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.disabled = function () {
|
||||
//Clear NR10:
|
||||
this.nr10 = 0;
|
||||
this.SweepFault = false;
|
||||
this.lastTimeSweep = 0;
|
||||
this.timeSweep = 0;
|
||||
this.frequencySweepDivider = 0;
|
||||
this.decreaseSweep = false;
|
||||
//Clear NR11:
|
||||
this.nr11 = 0;
|
||||
this.CachedDuty = 0xF0000000;
|
||||
this.totalLength = 0x40;
|
||||
//Clear NR12:
|
||||
this.nr12 = 0;
|
||||
this.envelopeVolume = 0;
|
||||
//Clear NR13:
|
||||
this.frequency = 0;
|
||||
this.FrequencyTracker = 0x8000;
|
||||
//Clear NR14:
|
||||
this.nr14 = 0;
|
||||
this.consecutive = true;
|
||||
this.ShadowFrequency = 0x8000;
|
||||
this.canPlay = false;
|
||||
this.Enabled = 0;
|
||||
this.envelopeSweeps = 0;
|
||||
this.envelopeSweepsLast = -1;
|
||||
this.FrequencyCounter = 0;
|
||||
this.DutyTracker = 0;
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.clockAudioLength = function () {
|
||||
if ((this.totalLength | 0) > 1) {
|
||||
this.totalLength = ((this.totalLength | 0) - 1) | 0;
|
||||
}
|
||||
else if ((this.totalLength | 0) == 1) {
|
||||
this.totalLength = 0;
|
||||
this.enableCheck();
|
||||
this.sound.unsetNR52(0xFE); //Channel #1 On Flag Off
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.enableCheck = function () {
|
||||
if ((this.consecutive || (this.totalLength | 0) > 0) && !this.SweepFault && this.canPlay) {
|
||||
this.Enabled = 0xF;
|
||||
}
|
||||
else {
|
||||
this.Enabled = 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.volumeEnableCheck = function () {
|
||||
this.canPlay = ((this.nr12 | 0) > 7);
|
||||
this.enableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.outputLevelCache = function () {
|
||||
var duty = this.CachedDuty >> (this.DutyTracker | 0);
|
||||
var envelopeVolume = this.envelopeVolume & this.Enabled & duty;
|
||||
this.currentSampleLeft = this.leftEnable & envelopeVolume;
|
||||
this.currentSampleRight = this.rightEnable & envelopeVolume;
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.setChannelOutputEnable = function (data) {
|
||||
data = data | 0;
|
||||
//Set by NR51 handler:
|
||||
this.rightEnable = (data << 31) >> 31;
|
||||
this.leftEnable = (data << 27) >> 31;
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.clockAudioSweep = function () {
|
||||
//Channel 1:
|
||||
if (!this.SweepFault && (this.timeSweep | 0) > 0) {
|
||||
this.timeSweep = ((this.timeSweep | 0) - 1) | 0
|
||||
if ((this.timeSweep | 0) == 0) {
|
||||
this.runAudioSweep();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.runAudioSweep = function () {
|
||||
//Channel 1:
|
||||
if ((this.lastTimeSweep | 0) > 0) {
|
||||
if ((this.frequencySweepDivider | 0) > 0) {
|
||||
this.Swept = true;
|
||||
if (this.decreaseSweep) {
|
||||
this.ShadowFrequency = ((this.ShadowFrequency | 0) - (this.ShadowFrequency >> (this.frequencySweepDivider | 0))) | 0;
|
||||
this.frequency = this.ShadowFrequency & 0x7FF;
|
||||
this.FrequencyTracker = (0x800 - (this.frequency | 0)) << 4;
|
||||
}
|
||||
else {
|
||||
this.ShadowFrequency = ((this.ShadowFrequency | 0) + (this.ShadowFrequency >> (this.frequencySweepDivider | 0))) | 0;
|
||||
this.frequency = this.ShadowFrequency | 0;
|
||||
if ((this.ShadowFrequency | 0) <= 0x7FF) {
|
||||
this.FrequencyTracker = (0x800 - (this.frequency | 0)) << 4;
|
||||
//Run overflow check twice:
|
||||
if ((((this.ShadowFrequency | 0) + (this.ShadowFrequency >> (this.frequencySweepDivider | 0))) | 0) > 0x7FF) {
|
||||
this.SweepFault = true;
|
||||
this.enableCheck();
|
||||
this.sound.unsetNR52(0xFE); //Channel #1 On Flag Off
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.frequency &= 0x7FF;
|
||||
this.SweepFault = true;
|
||||
this.enableCheck();
|
||||
this.sound.unsetNR52(0xFE); //Channel #1 On Flag Off
|
||||
}
|
||||
}
|
||||
this.timeSweep = this.lastTimeSweep | 0;
|
||||
}
|
||||
else {
|
||||
//Channel has sweep disabled and timer becomes a length counter:
|
||||
this.SweepFault = true;
|
||||
this.enableCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.audioSweepPerformDummy = function () {
|
||||
//Channel 1:
|
||||
if ((this.frequencySweepDivider | 0) > 0) {
|
||||
if (!this.decreaseSweep) {
|
||||
var channel1ShadowFrequency = ((this.ShadowFrequency | 0) + (this.ShadowFrequency >> (this.frequencySweepDivider | 0))) | 0;
|
||||
if ((channel1ShadowFrequency | 0) <= 0x7FF) {
|
||||
//Run overflow check twice:
|
||||
if ((((channel1ShadowFrequency | 0) + (channel1ShadowFrequency >> (this.frequencySweepDivider | 0))) | 0) > 0x7FF) {
|
||||
this.SweepFault = true;
|
||||
this.enableCheck();
|
||||
this.sound.unsetNR52(0xFE); //Channel #1 On Flag Off
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.SweepFault = true;
|
||||
this.enableCheck();
|
||||
this.sound.unsetNR52(0xFE); //Channel #1 On Flag Off
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.clockAudioEnvelope = function () {
|
||||
if ((this.envelopeSweepsLast | 0) > -1) {
|
||||
if ((this.envelopeSweeps | 0) > 0) {
|
||||
this.envelopeSweeps = ((this.envelopeSweeps | 0) - 1) | 0;
|
||||
}
|
||||
else {
|
||||
if (!this.envelopeType) {
|
||||
if ((this.envelopeVolume | 0) > 0) {
|
||||
this.envelopeVolume = ((this.envelopeVolume | 0) - 1) | 0;
|
||||
this.envelopeSweeps = this.envelopeSweepsLast | 0;
|
||||
}
|
||||
else {
|
||||
this.envelopeSweepsLast = -1;
|
||||
}
|
||||
}
|
||||
else if ((this.envelopeVolume | 0) < 0xF) {
|
||||
this.envelopeVolume = ((this.envelopeVolume | 0) + 1) | 0;
|
||||
this.envelopeSweeps = this.envelopeSweepsLast | 0;
|
||||
}
|
||||
else {
|
||||
this.envelopeSweepsLast = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.computeAudioChannel = function () {
|
||||
if ((this.FrequencyCounter | 0) == 0) {
|
||||
this.FrequencyCounter = this.FrequencyTracker | 0;
|
||||
this.DutyTracker = ((this.DutyTracker | 0) + 4) & 0x1C;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.readSOUND1CNT8_0 = function () {
|
||||
//NR10:
|
||||
return this.nr10 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.writeSOUND1CNT8_0 = function (data) {
|
||||
data = data | 0;
|
||||
//NR10:
|
||||
if (this.decreaseSweep && (data & 0x08) == 0) {
|
||||
if (this.Swept) {
|
||||
this.SweepFault = true;
|
||||
}
|
||||
}
|
||||
this.lastTimeSweep = (data & 0x70) >> 4;
|
||||
this.frequencySweepDivider = data & 0x07;
|
||||
this.decreaseSweep = ((data & 0x08) != 0);
|
||||
this.nr10 = data & 0xFF;
|
||||
this.enableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.readSOUND1CNT8_2 = function () {
|
||||
//NR11:
|
||||
return this.nr11 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.writeSOUND1CNT8_2 = function (data) {
|
||||
data = data | 0;
|
||||
//NR11:
|
||||
switch ((data >> 6) & 0x3) {
|
||||
case 0:
|
||||
this.CachedDuty = 0xF0000000;
|
||||
break;
|
||||
case 1:
|
||||
this.CachedDuty = 0xF000000F;
|
||||
break;
|
||||
case 2:
|
||||
this.CachedDuty = 0xFFF0000F;
|
||||
break;
|
||||
default:
|
||||
this.CachedDuty = 0x0FFFFFF0;
|
||||
}
|
||||
this.totalLength = (0x40 - (data & 0x3F)) | 0;
|
||||
this.nr11 = data & 0xFF;
|
||||
this.enableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.readSOUND1CNT8_3 = function () {
|
||||
//NR12:
|
||||
return this.nr12 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.writeSOUND1CNT8_3 = function (data) {
|
||||
data = data | 0;
|
||||
//NR12:
|
||||
this.envelopeType = ((data & 0x08) != 0);
|
||||
this.nr12 = data & 0xFF;
|
||||
this.volumeEnableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.writeSOUND1CNT_X0 = function (data) {
|
||||
data = data | 0;
|
||||
//NR13:
|
||||
this.frequency = (this.frequency & 0x700) | (data & 0xFF);
|
||||
this.FrequencyTracker = (0x800 - (this.frequency | 0)) << 4;
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.readSOUND1CNTX8 = function () {
|
||||
//NR14:
|
||||
return this.nr14 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel1Synth.prototype.writeSOUND1CNT_X1 = function (data) {
|
||||
data = data | 0;
|
||||
//NR14:
|
||||
this.consecutive = ((data & 0x40) == 0);
|
||||
this.frequency = ((data & 0x7) << 8) | (this.frequency & 0xFF);
|
||||
this.FrequencyTracker = (0x800 - (this.frequency | 0)) << 4;
|
||||
if ((data & 0x80) != 0) {
|
||||
//Reload nr10:
|
||||
this.timeSweep = this.lastTimeSweep | 0;
|
||||
this.Swept = false;
|
||||
//Reload nr12:
|
||||
this.envelopeVolume = this.nr12 >> 4;
|
||||
this.envelopeSweepsLast = ((this.nr12 & 0x7) - 1) | 0;
|
||||
if ((this.totalLength | 0) == 0) {
|
||||
this.totalLength = 0x40;
|
||||
}
|
||||
if ((this.lastTimeSweep | 0) > 0 || (this.frequencySweepDivider | 0) > 0) {
|
||||
this.sound.setNR52(0x1);
|
||||
}
|
||||
else {
|
||||
this.sound.unsetNR52(0xFE);
|
||||
}
|
||||
if ((data & 0x40) != 0) {
|
||||
this.sound.setNR52(0x1);
|
||||
}
|
||||
this.ShadowFrequency = this.frequency | 0;
|
||||
//Reset frequency overflow check + frequency sweep type check:
|
||||
this.SweepFault = false;
|
||||
//Supposed to run immediately:
|
||||
this.audioSweepPerformDummy();
|
||||
}
|
||||
this.enableCheck();
|
||||
this.nr14 = data & 0xFF;
|
||||
}
|
186
public/gfiles/gba/IodineGBA/core/sound/Channel2.js
Normal file
186
public/gfiles/gba/IodineGBA/core/sound/Channel2.js
Normal file
|
@ -0,0 +1,186 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceChannel2Synth(sound) {
|
||||
this.sound = sound;
|
||||
this.currentSampleLeft = 0;
|
||||
this.currentSampleRight = 0;
|
||||
this.CachedDuty = 0xF0000000;
|
||||
this.totalLength = 0x40;
|
||||
this.envelopeVolume = 0;
|
||||
this.frequency = 0;
|
||||
this.FrequencyTracker = 0x8000;
|
||||
this.consecutive = true;
|
||||
this.ShadowFrequency = 0x8000;
|
||||
this.canPlay = false;
|
||||
this.Enabled = 0;
|
||||
this.envelopeSweeps = 0;
|
||||
this.envelopeSweepsLast = -1;
|
||||
this.FrequencyCounter = 0;
|
||||
this.DutyTracker = 0;
|
||||
this.leftEnable = 0;
|
||||
this.rightEnable = 0;
|
||||
this.nr21 = 0;
|
||||
this.nr22 = 0;
|
||||
this.nr23 = 0;
|
||||
this.nr24 = 0;
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.disabled = function () {
|
||||
//Clear NR21:
|
||||
this.nr21 = 0;
|
||||
this.CachedDuty = 0xF0000000;
|
||||
this.totalLength = 0x40;
|
||||
//Clear NR22:
|
||||
this.nr22 = 0;
|
||||
this.envelopeVolume = 0;
|
||||
//Clear NR23:
|
||||
this.nr23 = 0;
|
||||
this.frequency = 0;
|
||||
this.FrequencyTracker = 0x8000;
|
||||
//Clear NR24:
|
||||
this.nr24 = 0;
|
||||
this.consecutive = true;
|
||||
this.canPlay = false;
|
||||
this.Enabled = 0;
|
||||
this.envelopeSweeps = 0;
|
||||
this.envelopeSweepsLast = -1;
|
||||
this.FrequencyCounter = 0;
|
||||
this.DutyTracker = 0;
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.clockAudioLength = function () {
|
||||
if ((this.totalLength | 0) > 1) {
|
||||
this.totalLength = ((this.totalLength | 0) - 1) | 0;
|
||||
}
|
||||
else if ((this.totalLength | 0) == 1) {
|
||||
this.totalLength = 0;
|
||||
this.enableCheck();
|
||||
this.sound.unsetNR52(0xFD); //Channel #2 On Flag Off
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.clockAudioEnvelope = function () {
|
||||
if ((this.envelopeSweepsLast | 0) > -1) {
|
||||
if ((this.envelopeSweeps | 0) > 0) {
|
||||
this.envelopeSweeps = ((this.envelopeSweeps | 0) - 1) | 0;
|
||||
}
|
||||
else {
|
||||
if (!this.envelopeType) {
|
||||
if ((this.envelopeVolume | 0) > 0) {
|
||||
this.envelopeVolume = ((this.envelopeVolume | 0) - 1) | 0;
|
||||
this.envelopeSweeps = this.envelopeSweepsLast | 0;
|
||||
}
|
||||
else {
|
||||
this.envelopeSweepsLast = -1;
|
||||
}
|
||||
}
|
||||
else if ((this.envelopeVolume | 0) < 0xF) {
|
||||
this.envelopeVolume = ((this.envelopeVolume | 0) + 1) | 0;
|
||||
this.envelopeSweeps = this.envelopeSweepsLast | 0;
|
||||
}
|
||||
else {
|
||||
this.envelopeSweepsLast = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.computeAudioChannel = function () {
|
||||
if ((this.FrequencyCounter | 0) == 0) {
|
||||
this.FrequencyCounter = this.FrequencyTracker | 0;
|
||||
this.DutyTracker = ((this.DutyTracker | 0) + 4) & 0x1C;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.enableCheck = function () {
|
||||
if ((this.consecutive || (this.totalLength | 0) > 0) && this.canPlay) {
|
||||
this.Enabled = 0xF;
|
||||
}
|
||||
else {
|
||||
this.Enabled = 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.volumeEnableCheck = function () {
|
||||
this.canPlay = ((this.nr22 | 0) > 7);
|
||||
this.enableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.outputLevelCache = function () {
|
||||
var duty = this.CachedDuty >> (this.DutyTracker | 0);
|
||||
var envelopeVolume = this.envelopeVolume & this.Enabled & duty;
|
||||
this.currentSampleLeft = this.leftEnable & envelopeVolume;
|
||||
this.currentSampleRight = this.rightEnable & envelopeVolume;
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.setChannelOutputEnable = function (data) {
|
||||
data = data | 0;
|
||||
//Set by NR51 handler:
|
||||
this.rightEnable = (data << 30) >> 31;
|
||||
this.leftEnable = (data << 26) >> 31;
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.readSOUND2CNT_L0 = function () {
|
||||
//NR21:
|
||||
return this.nr21 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.writeSOUND2CNT_L0 = function (data) {
|
||||
data = data | 0;
|
||||
//NR21:
|
||||
switch ((data >> 6) & 0x3) {
|
||||
case 0:
|
||||
this.CachedDuty = 0xF0000000;
|
||||
break;
|
||||
case 1:
|
||||
this.CachedDuty = 0xF000000F;
|
||||
break;
|
||||
case 2:
|
||||
this.CachedDuty = 0xFFF0000F;
|
||||
break;
|
||||
default:
|
||||
this.CachedDuty = 0x0FFFFFF0;
|
||||
}
|
||||
this.totalLength = (0x40 - (data & 0x3F)) | 0;
|
||||
this.nr21 = data & 0xFF;
|
||||
this.enableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.readSOUND2CNT_L1 = function () {
|
||||
//NR22:
|
||||
return this.nr22 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.writeSOUND2CNT_L1 = function (data) {
|
||||
data = data | 0;
|
||||
//NR22:
|
||||
this.envelopeType = ((data & 0x08) != 0);
|
||||
this.nr22 = data & 0xFF;
|
||||
this.volumeEnableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.writeSOUND2CNT_H0 = function (data) {
|
||||
data = data | 0;
|
||||
//NR23:
|
||||
this.frequency = (this.frequency & 0x700) | (data & 0xFF);
|
||||
this.FrequencyTracker = (0x800 - (this.frequency | 0)) << 4;
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.readSOUND2CNT_H = function () {
|
||||
//NR24:
|
||||
return this.nr24 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel2Synth.prototype.writeSOUND2CNT_H1 = function (data) {
|
||||
data = data | 0;
|
||||
//NR24:
|
||||
if ((data & 0x80) != 0) {
|
||||
//Reload nr22:
|
||||
this.envelopeVolume = this.nr22 >> 4;
|
||||
this.envelopeSweepsLast = ((this.nr22 & 0x7) - 1) | 0;
|
||||
if ((this.totalLength | 0) == 0) {
|
||||
this.totalLength = 0x40;
|
||||
}
|
||||
if ((data & 0x40) != 0) {
|
||||
this.sound.setNR52(0x2); //Channel #1 On Flag Off
|
||||
}
|
||||
}
|
||||
this.consecutive = ((data & 0x40) == 0x0);
|
||||
this.frequency = ((data & 0x7) << 8) | (this.frequency & 0xFF);
|
||||
this.FrequencyTracker = (0x800 - (this.frequency | 0)) << 4;
|
||||
this.nr24 = data & 0xFF;
|
||||
this.enableCheck();
|
||||
}
|
301
public/gfiles/gba/IodineGBA/core/sound/Channel3.js
Normal file
301
public/gfiles/gba/IodineGBA/core/sound/Channel3.js
Normal file
|
@ -0,0 +1,301 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceChannel3Synth(sound) {
|
||||
this.sound = sound;
|
||||
this.currentSampleLeft = 0;
|
||||
this.currentSampleRight = 0;
|
||||
this.lastSampleLookup = 0;
|
||||
this.canPlay = false;
|
||||
this.WAVERAMBankSpecified = 0;
|
||||
this.WAVERAMBankAccessed = 0x20;
|
||||
this.WaveRAMBankSize = 0x1F;
|
||||
this.totalLength = 0x100;
|
||||
this.patternType = 4;
|
||||
this.frequency = 0;
|
||||
this.FrequencyPeriod = 0x4000;
|
||||
this.consecutive = true;
|
||||
this.Enabled = 0;
|
||||
this.leftEnable = 0;
|
||||
this.rightEnable = 0;
|
||||
this.nr30 = 0;
|
||||
this.nr31 = 0;
|
||||
this.nr32 = 0;
|
||||
this.nr33 = 0;
|
||||
this.nr34 = 0;
|
||||
this.cachedSample = 0;
|
||||
this.PCM = getInt8Array(0x40);
|
||||
this.PCM16 = getUint16View(this.PCM);
|
||||
this.PCM32 = getInt32View(this.PCM);
|
||||
this.WAVERAM8 = getUint8Array(0x20);
|
||||
this.WAVERAM16 = getUint16View(this.WAVERAM8);
|
||||
this.WAVERAM32 = getInt32View(this.WAVERAM8);
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.disabled = function () {
|
||||
//Clear NR30:
|
||||
this.nr30 = 0;
|
||||
this.lastSampleLookup = 0;
|
||||
this.canPlay = false;
|
||||
this.WAVERAMBankSpecified = 0;
|
||||
this.WAVERAMBankAccessed = 0x20;
|
||||
this.WaveRAMBankSize = 0x1F;
|
||||
//Clear NR31:
|
||||
this.totalLength = 0x100;
|
||||
//Clear NR32:
|
||||
this.nr32 = 0;
|
||||
this.patternType = 4;
|
||||
//Clear NR33:
|
||||
this.nr33 = 0;
|
||||
this.frequency = 0;
|
||||
this.FrequencyPeriod = 0x4000;
|
||||
//Clear NR34:
|
||||
this.nr34 = 0;
|
||||
this.consecutive = true;
|
||||
this.Enabled = 0;
|
||||
this.counter = 0;
|
||||
}
|
||||
if (typeof Math.imul == "function") {
|
||||
//Math.imul found, insert the optimized path in:
|
||||
GameBoyAdvanceChannel3Synth.prototype.updateCache = function () {
|
||||
if ((this.patternType | 0) != 3) {
|
||||
this.cachedSample = this.PCM[this.lastSampleLookup | 0] >> (this.patternType | 0);
|
||||
}
|
||||
else {
|
||||
this.cachedSample = Math.imul(this.PCM[this.lastSampleLookup | 0] | 0, 3) >> 2;
|
||||
}
|
||||
this.outputLevelCache();
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Math.imul not found, use the compatibility method:
|
||||
GameBoyAdvanceChannel3Synth.prototype.updateCache = function () {
|
||||
if ((this.patternType | 0) != 3) {
|
||||
this.cachedSample = this.PCM[this.lastSampleLookup | 0] >> (this.patternType | 0);
|
||||
}
|
||||
else {
|
||||
this.cachedSample = (this.PCM[this.lastSampleLookup | 0] * 0.75) | 0;
|
||||
}
|
||||
this.outputLevelCache();
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.outputLevelCache = function () {
|
||||
var cachedSample = this.cachedSample & this.Enabled;
|
||||
this.currentSampleLeft = this.leftEnable & cachedSample;
|
||||
this.currentSampleRight = this.rightEnable & cachedSample;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.setChannelOutputEnable = function (data) {
|
||||
data = data | 0;
|
||||
//Set by NR51 handler:
|
||||
this.rightEnable = (data << 29) >> 31;
|
||||
this.leftEnable = (data << 25) >> 31;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.readWAVE8 = function (address) {
|
||||
address = ((address | 0) + (this.WAVERAMBankAccessed >> 1)) | 0;
|
||||
return this.WAVERAM8[address | 0] | 0;
|
||||
}
|
||||
if (__LITTLE_ENDIAN__) {
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeWAVE8 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
address = ((address | 0) + (this.WAVERAMBankAccessed >> 1)) | 0;
|
||||
this.WAVERAM8[address | 0] = data & 0xFF;
|
||||
var temp = ((data >> 4) & 0xF);
|
||||
temp = temp | ((data & 0xF) << 8);
|
||||
this.PCM16[address | 0] = temp | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeWAVE16 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
address = ((address | 0) + (this.WAVERAMBankAccessed >> 2)) | 0;
|
||||
this.WAVERAM16[address | 0] = data & 0xFFFF;
|
||||
var temp = ((data >> 4) & 0xF);
|
||||
temp = temp | ((data & 0xF) << 8);
|
||||
temp = temp | ((data & 0xF000) << 4);
|
||||
temp = temp | ((data & 0xF00) << 16);
|
||||
this.PCM32[address | 0] = temp | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeWAVE32 = function (address, data) {
|
||||
address = address | 0;
|
||||
data = data | 0;
|
||||
address = ((address | 0) + (this.WAVERAMBankAccessed >> 3)) | 0;
|
||||
this.WAVERAM32[address | 0] = data | 0;
|
||||
var temp = (data >> 4) & 0xF;
|
||||
temp = temp | ((data & 0xF) << 8);
|
||||
temp = temp | ((data & 0xF000) << 4);
|
||||
temp = temp | ((data & 0xF00) << 16);
|
||||
address = address << 1;
|
||||
this.PCM32[address | 0] = temp | 0;
|
||||
temp = (data >> 20) & 0xF;
|
||||
temp = temp | ((data >> 8) & 0xF00);
|
||||
temp = temp | ((data >> 12) & 0xF0000);
|
||||
temp = temp | (data & 0xF000000);
|
||||
this.PCM32[address | 1] = temp | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.readWAVE16 = function (address) {
|
||||
address = ((address | 0) + (this.WAVERAMBankAccessed >> 2)) | 0;
|
||||
return this.WAVERAM16[address | 0] | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.readWAVE32 = function (address) {
|
||||
address = ((address | 0) + (this.WAVERAMBankAccessed >> 3)) | 0;
|
||||
return this.WAVERAM32[address | 0] | 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeWAVE8 = function (address, data) {
|
||||
address += this.WAVERAMBankAccessed >> 1;
|
||||
this.WAVERAM8[address] = data & 0xFF;
|
||||
address <<= 1;
|
||||
this.PCM[address] = (data >> 4) & 0xF;
|
||||
this.PCM[address | 1] = data & 0xF;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeWAVE16 = function (address, data) {
|
||||
address += this.WAVERAMBankAccessed >> 2;
|
||||
address <<= 1;
|
||||
this.WAVERAM8[address] = data & 0xFF;
|
||||
this.WAVERAM8[address | 1] = (data >> 8) & 0xFF;
|
||||
address <<= 1;
|
||||
this.PCM[address] = (data >> 4) & 0xF;
|
||||
this.PCM[address | 1] = data & 0xF;
|
||||
this.PCM[address | 2] = (data >> 12) & 0xF;
|
||||
this.PCM[address | 3] = (data >> 8) & 0xF;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeWAVE32 = function (address, data) {
|
||||
address += this.WAVERAMBankAccessed >> 3;
|
||||
address <<= 2;
|
||||
this.WAVERAM8[address] = data & 0xFF;
|
||||
this.WAVERAM8[address | 1] = (data >> 8) & 0xFF;
|
||||
this.WAVERAM8[address | 2] = (data >> 16) & 0xFF;
|
||||
this.WAVERAM8[address | 3] = data >>> 24;
|
||||
address <<= 1;
|
||||
this.PCM[address] = (data >> 4) & 0xF;
|
||||
this.PCM[address | 1] = data & 0xF;
|
||||
this.PCM[address | 2] = (data >> 12) & 0xF;
|
||||
this.PCM[address | 3] = (data >> 8) & 0xF;
|
||||
this.PCM[address | 4] = (data >> 20) & 0xF;
|
||||
this.PCM[address | 5] = (data >> 16) & 0xF;
|
||||
this.PCM[address | 6] = data >>> 28;
|
||||
this.PCM[address | 7] = (data >> 24) & 0xF;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.readWAVE16 = function (address) {
|
||||
address += this.WAVERAMBankAccessed >> 1;
|
||||
return (this.WAVERAM8[address] | (this.WAVERAM8[address | 1] << 8));
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.readWAVE32 = function (address) {
|
||||
address += this.WAVERAMBankAccessed >> 1;
|
||||
return (this.WAVERAM8[address] | (this.WAVERAM8[address | 1] << 8) |
|
||||
(this.WAVERAM8[address | 2] << 16) | (this.WAVERAM8[address | 3] << 24));
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.enableCheck = function () {
|
||||
if (/*this.canPlay && */(this.consecutive || (this.totalLength | 0) > 0)) {
|
||||
this.Enabled = 0xF;
|
||||
}
|
||||
else {
|
||||
this.Enabled = 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.clockAudioLength = function () {
|
||||
if ((this.totalLength | 0) > 1) {
|
||||
this.totalLength = ((this.totalLength | 0) - 1) | 0;
|
||||
}
|
||||
else if ((this.totalLength | 0) == 1) {
|
||||
this.totalLength = 0;
|
||||
this.enableCheck();
|
||||
this.sound.unsetNR52(0xFB); //Channel #3 On Flag Off
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.computeAudioChannel = function () {
|
||||
if ((this.counter | 0) == 0) {
|
||||
if (this.canPlay) {
|
||||
this.lastSampleLookup = (((this.lastSampleLookup | 0) + 1) & this.WaveRAMBankSize) | this.WAVERAMBankSpecified;
|
||||
}
|
||||
this.counter = this.FrequencyPeriod | 0;
|
||||
}
|
||||
}
|
||||
|
||||
GameBoyAdvanceChannel3Synth.prototype.readSOUND3CNT_L = function () {
|
||||
//NR30:
|
||||
return this.nr30 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeSOUND3CNT_L = function (data) {
|
||||
data = data | 0;
|
||||
//NR30:
|
||||
if (!this.canPlay && (data & 0x80) != 0) {
|
||||
this.lastSampleLookup = 0;
|
||||
}
|
||||
this.canPlay = ((data & 0x80) != 0);
|
||||
this.WaveRAMBankSize = (data & 0x20) | 0x1F;
|
||||
this.WAVERAMBankSpecified = ((data & 0x40) >> 1) ^ (data & 0x20);
|
||||
this.WAVERAMBankAccessed = ((data & 0x40) >> 1) ^ 0x20;
|
||||
if (this.canPlay && (this.nr30 & 0x80) != 0 && !this.consecutive) {
|
||||
this.sound.setNR52(0x4);
|
||||
}
|
||||
this.nr30 = data & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeSOUND3CNT_H0 = function (data) {
|
||||
data = data | 0;
|
||||
//NR31:
|
||||
this.totalLength = (0x100 - (data & 0xFF)) | 0;
|
||||
this.enableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.readSOUND3CNT_H = function () {
|
||||
//NR32:
|
||||
return this.nr32 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeSOUND3CNT_H1 = function (data) {
|
||||
data = data | 0;
|
||||
//NR32:
|
||||
data = data & 0xFF;
|
||||
switch (data >> 5) {
|
||||
case 0:
|
||||
this.patternType = 4;
|
||||
break;
|
||||
case 1:
|
||||
this.patternType = 0;
|
||||
break;
|
||||
case 2:
|
||||
this.patternType = 1;
|
||||
break;
|
||||
case 3:
|
||||
this.patternType = 2;
|
||||
break;
|
||||
default:
|
||||
this.patternType = 3;
|
||||
}
|
||||
this.nr32 = data | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeSOUND3CNT_X0 = function (data) {
|
||||
data = data | 0;
|
||||
//NR33:
|
||||
this.frequency = (this.frequency & 0x700) | (data & 0xFF);
|
||||
this.FrequencyPeriod = (0x800 - (this.frequency | 0)) << 3;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.readSOUND3CNT_X = function () {
|
||||
//NR34:
|
||||
return this.nr34 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel3Synth.prototype.writeSOUND3CNT_X1 = function (data) {
|
||||
data = data | 0;
|
||||
//NR34:
|
||||
if ((data & 0x80) != 0) {
|
||||
if ((this.totalLength | 0) == 0) {
|
||||
this.totalLength = 0x100;
|
||||
}
|
||||
this.lastSampleLookup = 0;
|
||||
if ((data & 0x40) != 0) {
|
||||
this.sound.setNR52(0x4);
|
||||
}
|
||||
}
|
||||
this.consecutive = ((data & 0x40) == 0x0);
|
||||
this.frequency = ((data & 0x7) << 8) | (this.frequency & 0xFF);
|
||||
this.FrequencyPeriod = (0x800 - (this.frequency | 0)) << 3;
|
||||
this.enableCheck();
|
||||
this.nr34 = data & 0xFF;
|
||||
}
|
243
public/gfiles/gba/IodineGBA/core/sound/Channel4.js
Normal file
243
public/gfiles/gba/IodineGBA/core/sound/Channel4.js
Normal file
|
@ -0,0 +1,243 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceChannel4Synth(sound) {
|
||||
this.sound = sound;
|
||||
this.currentSampleLeft = 0;
|
||||
this.currentSampleRight = 0;
|
||||
this.totalLength = 0x40;
|
||||
this.envelopeVolume = 0;
|
||||
this.FrequencyPeriod = 32;
|
||||
this.lastSampleLookup = 0;
|
||||
this.BitRange = 0x7FFF;
|
||||
this.VolumeShifter = 15;
|
||||
this.currentVolume = 0;
|
||||
this.consecutive = true;
|
||||
this.envelopeSweeps = 0;
|
||||
this.envelopeSweepsLast = -1;
|
||||
this.canPlay = false;
|
||||
this.Enabled = 0;
|
||||
this.counter = 0;
|
||||
this.leftEnable = 0;
|
||||
this.rightEnable = 0;
|
||||
this.nr42 = 0;
|
||||
this.nr43 = 0;
|
||||
this.nr44 = 0;
|
||||
this.cachedSample = 0;
|
||||
this.intializeWhiteNoise();
|
||||
this.noiseSampleTable = this.LSFR15Table;
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.intializeWhiteNoise = function () {
|
||||
//Noise Sample Tables:
|
||||
var randomFactor = 1;
|
||||
//15-bit LSFR Cache Generation:
|
||||
this.LSFR15Table = getInt8Array(0x80000);
|
||||
var LSFR = 0x7FFF; //Seed value has all its bits set.
|
||||
var LSFRShifted = 0x3FFF;
|
||||
for (var index = 0; index < 0x8000; ++index) {
|
||||
//Normalize the last LSFR value for usage:
|
||||
randomFactor = 1 - (LSFR & 1); //Docs say it's the inverse.
|
||||
//Cache the different volume level results:
|
||||
this.LSFR15Table[0x08000 | index] = randomFactor;
|
||||
this.LSFR15Table[0x10000 | index] = randomFactor * 0x2;
|
||||
this.LSFR15Table[0x18000 | index] = randomFactor * 0x3;
|
||||
this.LSFR15Table[0x20000 | index] = randomFactor * 0x4;
|
||||
this.LSFR15Table[0x28000 | index] = randomFactor * 0x5;
|
||||
this.LSFR15Table[0x30000 | index] = randomFactor * 0x6;
|
||||
this.LSFR15Table[0x38000 | index] = randomFactor * 0x7;
|
||||
this.LSFR15Table[0x40000 | index] = randomFactor * 0x8;
|
||||
this.LSFR15Table[0x48000 | index] = randomFactor * 0x9;
|
||||
this.LSFR15Table[0x50000 | index] = randomFactor * 0xA;
|
||||
this.LSFR15Table[0x58000 | index] = randomFactor * 0xB;
|
||||
this.LSFR15Table[0x60000 | index] = randomFactor * 0xC;
|
||||
this.LSFR15Table[0x68000 | index] = randomFactor * 0xD;
|
||||
this.LSFR15Table[0x70000 | index] = randomFactor * 0xE;
|
||||
this.LSFR15Table[0x78000 | index] = randomFactor * 0xF;
|
||||
//Recompute the LSFR algorithm:
|
||||
LSFRShifted = LSFR >> 1;
|
||||
LSFR = LSFRShifted | (((LSFRShifted ^ LSFR) & 0x1) << 14);
|
||||
}
|
||||
//7-bit LSFR Cache Generation:
|
||||
this.LSFR7Table = getInt8Array(0x800);
|
||||
LSFR = 0x7F; //Seed value has all its bits set.
|
||||
for (index = 0; index < 0x80; ++index) {
|
||||
//Normalize the last LSFR value for usage:
|
||||
randomFactor = 1 - (LSFR & 1); //Docs say it's the inverse.
|
||||
//Cache the different volume level results:
|
||||
this.LSFR7Table[0x080 | index] = randomFactor;
|
||||
this.LSFR7Table[0x100 | index] = randomFactor * 0x2;
|
||||
this.LSFR7Table[0x180 | index] = randomFactor * 0x3;
|
||||
this.LSFR7Table[0x200 | index] = randomFactor * 0x4;
|
||||
this.LSFR7Table[0x280 | index] = randomFactor * 0x5;
|
||||
this.LSFR7Table[0x300 | index] = randomFactor * 0x6;
|
||||
this.LSFR7Table[0x380 | index] = randomFactor * 0x7;
|
||||
this.LSFR7Table[0x400 | index] = randomFactor * 0x8;
|
||||
this.LSFR7Table[0x480 | index] = randomFactor * 0x9;
|
||||
this.LSFR7Table[0x500 | index] = randomFactor * 0xA;
|
||||
this.LSFR7Table[0x580 | index] = randomFactor * 0xB;
|
||||
this.LSFR7Table[0x600 | index] = randomFactor * 0xC;
|
||||
this.LSFR7Table[0x680 | index] = randomFactor * 0xD;
|
||||
this.LSFR7Table[0x700 | index] = randomFactor * 0xE;
|
||||
this.LSFR7Table[0x780 | index] = randomFactor * 0xF;
|
||||
//Recompute the LSFR algorithm:
|
||||
LSFRShifted = LSFR >> 1;
|
||||
LSFR = LSFRShifted | (((LSFRShifted ^ LSFR) & 0x1) << 6);
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.disabled = function () {
|
||||
//Clear NR41:
|
||||
this.totalLength = 0x40;
|
||||
//Clear NR42:
|
||||
this.nr42 = 0;
|
||||
this.envelopeVolume = 0;
|
||||
//Clear NR43:
|
||||
this.nr43 = 0;
|
||||
this.FrequencyPeriod = 32;
|
||||
this.lastSampleLookup = 0;
|
||||
this.BitRange = 0x7FFF;
|
||||
this.VolumeShifter = 15;
|
||||
this.currentVolume = 0;
|
||||
this.noiseSampleTable = this.LSFR15Table;
|
||||
//Clear NR44:
|
||||
this.nr44 = 0;
|
||||
this.consecutive = true;
|
||||
this.envelopeSweeps = 0;
|
||||
this.envelopeSweepsLast = -1;
|
||||
this.canPlay = false;
|
||||
this.Enabled = 0;
|
||||
this.counter = 0;
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.clockAudioLength = function () {
|
||||
if ((this.totalLength | 0) > 1) {
|
||||
this.totalLength = ((this.totalLength | 0) - 1) | 0;
|
||||
}
|
||||
else if ((this.totalLength | 0) == 1) {
|
||||
this.totalLength = 0;
|
||||
this.enableCheck();
|
||||
this.sound.unsetNR52(0xF7); //Channel #4 On Flag Off
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.clockAudioEnvelope = function () {
|
||||
if ((this.envelopeSweepsLast | 0) > -1) {
|
||||
if ((this.envelopeSweeps | 0) > 0) {
|
||||
this.envelopeSweeps = ((this.envelopeSweeps | 0) - 1) | 0;
|
||||
}
|
||||
else {
|
||||
if (!this.envelopeType) {
|
||||
if ((this.envelopeVolume | 0) > 0) {
|
||||
this.envelopeVolume = ((this.envelopeVolume | 0) - 1) | 0;
|
||||
this.currentVolume = (this.envelopeVolume | 0) << (this.VolumeShifter | 0);
|
||||
this.envelopeSweeps = this.envelopeSweepsLast | 0;
|
||||
}
|
||||
else {
|
||||
this.envelopeSweepsLast = -1;
|
||||
}
|
||||
}
|
||||
else if ((this.envelopeVolume | 0) < 0xF) {
|
||||
this.envelopeVolume = ((this.envelopeVolume | 0) + 1) | 0;
|
||||
this.currentVolume = (this.envelopeVolume | 0) << (this.VolumeShifter | 0);
|
||||
this.envelopeSweeps = this.envelopeSweepsLast | 0;
|
||||
}
|
||||
else {
|
||||
this.envelopeSweepsLast = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.computeAudioChannel = function () {
|
||||
if ((this.counter | 0) == 0) {
|
||||
this.lastSampleLookup = ((this.lastSampleLookup | 0) + 1) & this.BitRange;
|
||||
this.counter = this.FrequencyPeriod | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.enableCheck = function () {
|
||||
if ((this.consecutive || (this.totalLength | 0) > 0) && this.canPlay) {
|
||||
this.Enabled = 0xF;
|
||||
}
|
||||
else {
|
||||
this.Enabled = 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.volumeEnableCheck = function () {
|
||||
this.canPlay = ((this.nr42 | 0) > 7);
|
||||
this.enableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.outputLevelCache = function () {
|
||||
var cachedSample = this.cachedSample & this.Enabled;
|
||||
this.currentSampleLeft = this.leftEnable & cachedSample;
|
||||
this.currentSampleRight = this.rightEnable & cachedSample;
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.setChannelOutputEnable = function (data) {
|
||||
data = data | 0;
|
||||
//Set by NR51 handler:
|
||||
this.rightEnable = (data << 28) >> 31;
|
||||
this.leftEnable = (data << 24) >> 31;
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.updateCache = function () {
|
||||
this.cachedSample = this.noiseSampleTable[this.currentVolume | this.lastSampleLookup] | 0;
|
||||
this.outputLevelCache();
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.writeSOUND4CNT_L0 = function (data) {
|
||||
data = data | 0;
|
||||
//NR41:
|
||||
this.totalLength = (0x40 - (data & 0x3F)) | 0;
|
||||
this.enableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.writeSOUND4CNT_L1 = function (data) {
|
||||
data = data | 0;
|
||||
//NR42:
|
||||
this.envelopeType = ((data & 0x08) != 0);
|
||||
this.nr42 = data & 0xFF;
|
||||
this.volumeEnableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.readSOUND4CNT_L = function () {
|
||||
//NR42:
|
||||
return this.nr42 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.writeSOUND4CNT_H0 = function (data) {
|
||||
data = data | 0;
|
||||
//NR43:
|
||||
this.FrequencyPeriod = Math.max((data & 0x7) << 4, 8) << ((((data >> 4) & 0xF) + 2) | 0);
|
||||
var bitWidth = data & 0x8;
|
||||
if (((bitWidth | 0) == 0x8 && (this.BitRange | 0) == 0x7FFF) || ((bitWidth | 0) == 0 && (this.BitRange | 0) == 0x7F)) {
|
||||
this.lastSampleLookup = 0;
|
||||
this.BitRange = ((bitWidth | 0) == 0x8) ? 0x7F : 0x7FFF;
|
||||
this.VolumeShifter = ((bitWidth | 0) == 0x8) ? 7 : 15;
|
||||
this.currentVolume = this.envelopeVolume << (this.VolumeShifter | 0);
|
||||
this.noiseSampleTable = ((bitWidth | 0) == 0x8) ? this.LSFR7Table : this.LSFR15Table;
|
||||
}
|
||||
this.nr43 = data & 0xFF;
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.readSOUND4CNT_H0 = function () {
|
||||
//NR43:
|
||||
return this.nr43 | 0;
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.writeSOUND4CNT_H1 = function (data) {
|
||||
data = data | 0;
|
||||
//NR44:
|
||||
this.nr44 = data & 0xFF;
|
||||
this.consecutive = ((data & 0x40) == 0x0);
|
||||
if ((data & 0x80) != 0) {
|
||||
this.envelopeVolume = this.nr42 >> 4;
|
||||
this.currentVolume = this.envelopeVolume << (this.VolumeShifter | 0);
|
||||
this.envelopeSweepsLast = ((this.nr42 & 0x7) - 1) | 0;
|
||||
if ((this.totalLength | 0) == 0) {
|
||||
this.totalLength = 0x40;
|
||||
}
|
||||
if ((data & 0x40) != 0) {
|
||||
this.sound.setNR52(0x8);
|
||||
}
|
||||
}
|
||||
this.enableCheck();
|
||||
}
|
||||
GameBoyAdvanceChannel4Synth.prototype.readSOUND4CNT_H1 = function () {
|
||||
//NR44:
|
||||
return this.nr44 | 0;
|
||||
}
|
63
public/gfiles/gba/IodineGBA/core/sound/FIFO.js
Normal file
63
public/gfiles/gba/IodineGBA/core/sound/FIFO.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GameBoyAdvanceFIFO() {
|
||||
this.count = 0;
|
||||
this.position = 0;
|
||||
this.buffer = getInt8Array(0x20);
|
||||
}
|
||||
GameBoyAdvanceFIFO.prototype.push = function (sample) {
|
||||
sample = sample | 0;
|
||||
var writePosition = ((this.position | 0) + (this.count | 0)) | 0;
|
||||
this.buffer[writePosition & 0x1F] = (sample << 24) >> 24;
|
||||
if ((this.count | 0) < 0x20) {
|
||||
//Should we cap at 0x20 or overflow back to 0 and reset queue?
|
||||
this.count = ((this.count | 0) + 1) | 0;
|
||||
}
|
||||
}
|
||||
GameBoyAdvanceFIFO.prototype.push8 = function (sample) {
|
||||
sample = sample | 0;
|
||||
this.push(sample | 0);
|
||||
this.push(sample | 0);
|
||||
this.push(sample | 0);
|
||||
this.push(sample | 0);
|
||||
}
|
||||
GameBoyAdvanceFIFO.prototype.push16 = function (sample) {
|
||||
sample = sample | 0;
|
||||
this.push(sample | 0);
|
||||
this.push(sample >> 8);
|
||||
this.push(sample | 0);
|
||||
this.push(sample >> 8);
|
||||
}
|
||||
GameBoyAdvanceFIFO.prototype.push32 = function (sample) {
|
||||
sample = sample | 0;
|
||||
this.push(sample | 0);
|
||||
this.push(sample >> 8);
|
||||
this.push(sample >> 16);
|
||||
this.push(sample >> 24);
|
||||
}
|
||||
GameBoyAdvanceFIFO.prototype.shift = function () {
|
||||
var output = 0;
|
||||
if ((this.count | 0) > 0) {
|
||||
this.count = ((this.count | 0) - 1) | 0;
|
||||
output = this.buffer[this.position & 0x1F] << 3;
|
||||
this.position = ((this.position | 0) + 1) & 0x1F;
|
||||
}
|
||||
return output | 0;
|
||||
}
|
||||
GameBoyAdvanceFIFO.prototype.requestingDMA = function () {
|
||||
return ((this.count | 0) <= 0x10);
|
||||
}
|
||||
GameBoyAdvanceFIFO.prototype.samplesUntilDMATrigger = function () {
|
||||
return ((this.count | 0) - 0x10) | 0;
|
||||
}
|
||||
GameBoyAdvanceFIFO.prototype.clear = function () {
|
||||
this.count = 0;
|
||||
}
|
186
public/gfiles/gba/IodineGBA/includes/TypedArrayShim.js
Normal file
186
public/gfiles/gba/IodineGBA/includes/TypedArrayShim.js
Normal file
|
@ -0,0 +1,186 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function getInt8Array(size_t) {
|
||||
try {
|
||||
return new Int8Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return getArray(size_t);
|
||||
}
|
||||
}
|
||||
function getUint8Array(size_t) {
|
||||
try {
|
||||
return new Uint8Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return getArray(size_t);
|
||||
}
|
||||
}
|
||||
function getUint8View(typed_array) {
|
||||
try {
|
||||
return new Uint8Array(typed_array.buffer);
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function getSharedUint8Array(size_t) {
|
||||
try {
|
||||
//Compatibility for older Firefox Nightlies:
|
||||
return new SharedUint8Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return new Uint8Array(new SharedArrayBuffer(size_t));
|
||||
}
|
||||
}
|
||||
function getInt16Array(size_t) {
|
||||
try {
|
||||
return new Int16Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return getArray(size_t);
|
||||
}
|
||||
}
|
||||
function getUint16Array(size_t) {
|
||||
try {
|
||||
return new Uint16Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return getArray(size_t);
|
||||
}
|
||||
}
|
||||
function getUint16View(typed_array) {
|
||||
try {
|
||||
return new Uint16Array(typed_array.buffer);
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function getInt32Array(size_t) {
|
||||
try {
|
||||
return new Int32Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return getArray(size_t);
|
||||
}
|
||||
}
|
||||
function getInt32View(typed_array) {
|
||||
try {
|
||||
return new Int32Array(typed_array.buffer);
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function getInt32ViewCustom(typed_array, start, end) {
|
||||
try {
|
||||
typed_array = getInt32View(typed_array);
|
||||
return typed_array.subarray(start, end);
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
//Nightly Firefox 4 used to have the subarray function named as slice:
|
||||
return typed_array.slice(start, end);
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
function getSharedInt32Array(size_t) {
|
||||
try {
|
||||
//Compatibility for older Firefox Nightlies:
|
||||
return new SharedInt32Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return new Int32Array(new SharedArrayBuffer(size_t << 2));
|
||||
}
|
||||
}
|
||||
function getUint8ViewCustom(typed_array, start, end) {
|
||||
try {
|
||||
typed_array = getUint8View(typed_array);
|
||||
return typed_array.subarray(start, end);
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
//Nightly Firefox 4 used to have the subarray function named as slice:
|
||||
return typed_array.slice(start, end);
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
function getUint32Array(size_t) {
|
||||
try {
|
||||
return new Uint32Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return getArray(size_t);
|
||||
}
|
||||
}
|
||||
function getSharedUint32Array(size_t) {
|
||||
try {
|
||||
//Compatibility for older Firefox Nightlies:
|
||||
return new SharedUint32Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return new Uint32Array(new SharedArrayBuffer(size_t << 2));
|
||||
}
|
||||
}
|
||||
function getFloat32Array(size_t) {
|
||||
try {
|
||||
return new Float32Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return getArray(size_t);
|
||||
}
|
||||
}
|
||||
function getSharedFloat32Array(size_t) {
|
||||
try {
|
||||
//Compatibility for older Firefox Nightlies:
|
||||
return new SharedFloat32Array(size_t);
|
||||
}
|
||||
catch (error) {
|
||||
return new Float32Array(new SharedArrayBuffer(size_t << 2));
|
||||
}
|
||||
}
|
||||
function getArray(size_t) {
|
||||
var genericArray = [];
|
||||
for (var size_index = 0; size_index < size_t; ++size_index) {
|
||||
genericArray[size_index] = 0;
|
||||
}
|
||||
return genericArray;
|
||||
}
|
||||
var __VIEWS_SUPPORTED__ = getUint16View(getInt32Array(1)) !== null;
|
||||
var __LITTLE_ENDIAN__ = (function () {
|
||||
if (__VIEWS_SUPPORTED__) {
|
||||
var test = getInt32Array(1);
|
||||
test[0] = 1;
|
||||
var test2 = getUint16View(test);
|
||||
if (test2[0] == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})();
|
||||
if (typeof Atomics == "object") {
|
||||
if (typeof Atomics.futexWait == "function" && typeof Atomics.wait == "undefined") {
|
||||
//Polyfill in deprecated call names:
|
||||
Atomics.wait = Atomics.futexWait;
|
||||
Atomics.notify = Atomics.futexWake;
|
||||
}
|
||||
else if (typeof Atomics.wake == "function" && typeof Atomics.notify == "undefined") {
|
||||
//Polyfill in deprecated call names:
|
||||
Atomics.notify = Atomics.wake;
|
||||
}
|
||||
}
|
BIN
public/gfiles/gba/bios.bin
Normal file
BIN
public/gfiles/gba/bios.bin
Normal file
Binary file not shown.
128
public/gfiles/gba/index.html
Normal file
128
public/gfiles/gba/index.html
Normal file
|
@ -0,0 +1,128 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>GBA</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=160">
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
|
||||
<!--Required Scripts-->
|
||||
<script src="IodineGBA/includes/TypedArrayShim.js"></script>
|
||||
<script src="IodineGBA/core/Cartridge.js"></script>
|
||||
<script src="IodineGBA/core/DMA.js"></script>
|
||||
<script src="IodineGBA/core/Emulator.js"></script>
|
||||
<script src="IodineGBA/core/Graphics.js"></script>
|
||||
<script src="IodineGBA/core/RunLoop.js"></script>
|
||||
<script src="IodineGBA/core/Memory.js"></script>
|
||||
<script src="IodineGBA/core/IRQ.js"></script>
|
||||
<script src="IodineGBA/core/JoyPad.js"></script>
|
||||
<script src="IodineGBA/core/Serial.js"></script>
|
||||
<script src="IodineGBA/core/Sound.js"></script>
|
||||
<script src="IodineGBA/core/Timer.js"></script>
|
||||
<script src="IodineGBA/core/Wait.js"></script>
|
||||
<script src="IodineGBA/core/CPU.js"></script>
|
||||
<script src="IodineGBA/core/Saves.js"></script>
|
||||
<script src="IodineGBA/core/sound/FIFO.js"></script>
|
||||
<script src="IodineGBA/core/sound/Channel1.js"></script>
|
||||
<script src="IodineGBA/core/sound/Channel2.js"></script>
|
||||
<script src="IodineGBA/core/sound/Channel3.js"></script>
|
||||
<script src="IodineGBA/core/sound/Channel4.js"></script>
|
||||
<script src="IodineGBA/core/CPU/ARM.js"></script>
|
||||
<script src="IodineGBA/core/CPU/THUMB.js"></script>
|
||||
<script src="IodineGBA/core/CPU/CPSR.js"></script>
|
||||
<script src="IodineGBA/core/graphics/Renderer.js"></script>
|
||||
<script src="IodineGBA/core/graphics/RendererShim.js"></script>
|
||||
<script src="IodineGBA/core/graphics/RendererProxy.js"></script>
|
||||
<script src="IodineGBA/core/graphics/BGTEXT.js"></script>
|
||||
<script src="IodineGBA/core/graphics/BG2FrameBuffer.js"></script>
|
||||
<script src="IodineGBA/core/graphics/BGMatrix.js"></script>
|
||||
<script src="IodineGBA/core/graphics/AffineBG.js"></script>
|
||||
<script src="IodineGBA/core/graphics/ColorEffects.js"></script>
|
||||
<script src="IodineGBA/core/graphics/Mosaic.js"></script>
|
||||
<script src="IodineGBA/core/graphics/OBJ.js"></script>
|
||||
<script src="IodineGBA/core/graphics/OBJWindow.js"></script>
|
||||
<script src="IodineGBA/core/graphics/Window.js"></script>
|
||||
<script src="IodineGBA/core/graphics/Compositor.js"></script>
|
||||
<script src="IodineGBA/core/memory/DMA0.js"></script>
|
||||
<script src="IodineGBA/core/memory/DMA1.js"></script>
|
||||
<script src="IodineGBA/core/memory/DMA2.js"></script>
|
||||
<script src="IodineGBA/core/memory/DMA3.js"></script>
|
||||
<script src="IodineGBA/core/cartridge/SaveDeterminer.js"></script>
|
||||
<script src="IodineGBA/core/cartridge/SRAM.js"></script>
|
||||
<script src="IodineGBA/core/cartridge/FLASH.js"></script>
|
||||
<script src="IodineGBA/core/cartridge/EEPROM.js"></script>
|
||||
<script src="IodineGBA/core/cartridge/GPIO.js"></script>
|
||||
<!--Add your webpage scripts below-->
|
||||
<script src="user_scripts/AudioGlueCode.js"></script>
|
||||
<script src="user_scripts/base64.js"></script>
|
||||
<script src="user_scripts/CoreGlueCode.js"></script>
|
||||
<script src="user_scripts/GfxGlueCode.js"></script>
|
||||
<script src="user_scripts/GUIGlueCode.js"></script>
|
||||
<script src="user_scripts/JoyPadGlueCode.js"></script>
|
||||
<script src="user_scripts/ROMLoadGlueCode.js"></script>
|
||||
<script src="user_scripts/SavesGlueCode.js"></script>
|
||||
<script src="user_scripts/WorkerGfxGlueCode.js"></script>
|
||||
<script src="user_scripts/WorkerGlueCode.js"></script>
|
||||
<script src="user_scripts/XAudioJS/swfobject.js"></script>
|
||||
<script src="user_scripts/XAudioJS/resampler.js"></script>
|
||||
<script src="user_scripts/XAudioJS/XAudioServer.js"></script>
|
||||
<link rel="stylesheet" href="user_css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<!-- Minified Useless -->
|
||||
<div id="menu" class="paused"> <ul id="menu_top"> <li> File <ul> <li><span>BIOS: </span> <input type="file" id="bios_load" class="files"></li><li><span>Game: </span> <input type="file" id="rom_load" class="files"></li></ul> </li><li id="play" class="show">Play</li><li id="pause" class="hide">Pause</li><li id="restart">Restart</li><li> Settings <ul> <li> <input type="checkbox" id="skip_boot" checked="checked"> Skip Boot Intro </li><li> <input type="checkbox" id="toggleSmoothScaling"> Smooth Scaling </li><li> <input type="checkbox" id="toggleDynamicSpeed"> Dynamic Speed </li><li> <input type="checkbox" id="offthread-cpu" checked="checked"> CPU off-thread </li><li> <input type="checkbox" id="offthread-gpu" checked="checked"> GPU off-thread </li><li> <input type="checkbox" id="sound"> Sound </li><li> GBA Bindings <ul> <li id="key_a"> <span>A</span> </li><li id="key_b"> <span>B</span> </li><li id="key_l"> <span>L</span> </li><li id="key_r"> <span>R</span> </li><li id="key_start"> <span>Start</span> </li><li id="key_select"> <span>Select</span> </li><li id="key_up"> <span>↑</span> </li><li id="key_down"> <span>↓</span> </li><li id="key_left"> <span>←</span> </li><li id="key_right"> <span>→</span> </li></ul> </li><li> Emulator Bindings <ul> <li id="key_volumeup"> <span>Volume Up</span> </li><li id="key_volumedown"> <span>Volume Down</span> </li><li id="key_speedup"> <span>Speed Up</span> </li><li id="key_slowdown"> <span>Slow Down</span> </li><li id="key_speedreset"> <span>Speed Reset</span> </li><li id="key_fullscreen"> <span>Fullscreen</span> </li><li id="key_playpause"> <span>Play/Pause</span> </li><li id="key_restart"> <span>Restart</span> </li></ul> </li></ul> </li><li> Volume <ul> <li> <input type="range" id="volume"> </li></ul> </li><li id="fullscreen">Fullscreen</li><li> <span id="speed">Speed</span> <ul> <li> <input type="range" id="speedset"> </li></ul> </li></ul> </div>
|
||||
<!-- End useless -->
|
||||
<ul class="menu">
|
||||
<li>Controls<ul>
|
||||
<li>DPad: Arrow keys</li>
|
||||
<li>Start: Enter</li>
|
||||
<li>Select: Space</li>
|
||||
<li>A Button: D</li>
|
||||
<li>B Button: C</li>
|
||||
<li>L Bumper: S</li>
|
||||
<li>R Bumper: X</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<input type="checkbox" id="smooth" onclick="setSmooth()">Smooth
|
||||
</li>
|
||||
<li id="saves_menu">Saves<ul id="saves_menu_container">
|
||||
<li>Import: <input type="file" id="import" class="files" accept=".export">
|
||||
<label for="import">Upload Save</label>
|
||||
</li>
|
||||
<li>
|
||||
<a href="./" id="export" target="_new">Export All Saves</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="ffd" style="display: none;">
|
||||
<h2>Upload GBA ROM</h2>
|
||||
<input type="file" id="upload" accept=".gba" onchange="gba_upload(this)" />
|
||||
<label for="upload">Choose File</label>
|
||||
</div>
|
||||
<div id="main">
|
||||
<canvas class="canvas" id="emulator_target" width="240" height="160" oncontextmenu="event.preventDefault()"></canvas>
|
||||
</div>
|
||||
<div class="touch-controls">
|
||||
<div class="touch-dpad">
|
||||
<button id="touch-up">↑</button><br>
|
||||
<button id="touch-left">←</button>
|
||||
<button id="touch-right">→</button><br>
|
||||
<button id="touch-down">↓</button>
|
||||
</div>
|
||||
<div class="touch-buttons">
|
||||
<button id="touch-select">SELECT</button>
|
||||
<button id="touch-start">START</button>
|
||||
</div>
|
||||
<div class="touch-buttons">
|
||||
<button id="touch-a">A</button>
|
||||
<button id="touch-b">B</button><br>
|
||||
<button id="touch-l">L</button>
|
||||
<button id="touch-r">R</button>
|
||||
</div>
|
||||
</div>
|
||||
<span class="message" id="tempMessage"></span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
281
public/gfiles/gba/user_css/main.css
Normal file
281
public/gfiles/gba/user_css/main.css
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
|-----------------------------------------
|
||||
| Core CSS
|
||||
|-----------------------------------------
|
||||
*/
|
||||
|
||||
html, body {
|
||||
font-family: Open Sans, Arial, sans-serif;
|
||||
height: 100%;
|
||||
width:100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #000;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* reset all list items */
|
||||
ul{
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#main {
|
||||
position:absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
/*
|
||||
|-----------------------------------------
|
||||
| Canvas
|
||||
|-----------------------------------------
|
||||
|
|
||||
| Classes are automatically overwritten
|
||||
| by the filter styles, therefore only
|
||||
| attributes and id's can be used.
|
||||
|
|
||||
*/
|
||||
|
||||
canvas {
|
||||
margin: auto;
|
||||
display: block;
|
||||
padding: 0px;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
canvas.textureSmooth {
|
||||
image-rendering: auto;
|
||||
image-rendering: optimizeQuality;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
canvas.texturePixelated {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: -o-crisp-edges;
|
||||
image-rendering: -moz-crisp-edges;
|
||||
image-rendering: crisp-edges;
|
||||
image-rendering: pixelated;
|
||||
-ms-interpolation-mode: nearest-neighbor;
|
||||
}
|
||||
|
||||
/*
|
||||
|-----------------------------------------
|
||||
| Messages
|
||||
|-----------------------------------------
|
||||
*/
|
||||
|
||||
.message {
|
||||
background: #6cc27d;
|
||||
padding: 1em 2em;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
bottom: 0px;
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
display: none;
|
||||
font-weight: bold;
|
||||
vertical-align: bottom;
|
||||
font-family: monospace;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|-----------------------------------------
|
||||
| Main Menu
|
||||
|-----------------------------------------
|
||||
*/
|
||||
|
||||
/* top level menu */
|
||||
div#menu {
|
||||
display: none !important;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
ul{
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background: #fff;
|
||||
transition: .3s ease;
|
||||
cursor: pointer;
|
||||
font-family: sans-serif;
|
||||
z-index: 1;
|
||||
opacity: 0;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
.menu:hover{opacity: 0.9;}
|
||||
|
||||
.menu ul{
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top:100%;
|
||||
left:0;
|
||||
background-color: rgb(245, 245, 245);
|
||||
box-shadow: 0 5px 10px 0 rgba(0,0,0,.1);
|
||||
transition: .3s ease;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.menu ul li {
|
||||
padding: .3em 1em !important;
|
||||
}
|
||||
|
||||
.menu li{
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
cursor:pointer;
|
||||
padding: .7em 1em;
|
||||
}
|
||||
|
||||
.menu li:hover {
|
||||
background: rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.menu li:hover > ul{
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
li #smooth {
|
||||
transform: scale(1.5);
|
||||
margin: 0px 13px 0px 0px;
|
||||
}
|
||||
|
||||
#import {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#import + label {
|
||||
border: 1px solid rgb(118, 118, 118);
|
||||
border-radius: 2px;
|
||||
padding: 4px;
|
||||
margin: 2px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#export {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#ffd {
|
||||
z-index: 5;
|
||||
height: 200px;
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
background: #ddd;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
font-family: sans-serif;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#upload {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#upload + label {
|
||||
border: 1px solid rgb(118, 118, 118);
|
||||
border-radius: 2px;
|
||||
padding: 4px;
|
||||
margin: 10px;
|
||||
font-size: 13px;
|
||||
background-color: white;
|
||||
display: inline-block;
|
||||
transition: ease .1s;
|
||||
}
|
||||
|
||||
#upload + label:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
/*
|
||||
|-----------------------------------------
|
||||
| Touch Controls
|
||||
|-----------------------------------------
|
||||
*/
|
||||
|
||||
.touch-controls{
|
||||
display: flex;
|
||||
padding: 1em;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.touch-controls button{
|
||||
display: inline-block;
|
||||
-webkit-appearance: none;
|
||||
border:0;
|
||||
outline: 0;
|
||||
background: #fff;
|
||||
opacity: 0.7;
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
line-height: 3em;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: .1s ease;
|
||||
margin:.5em;
|
||||
}
|
||||
|
||||
.touch-controls button:active{
|
||||
transform: scale(0.95);
|
||||
box-shadow: 0 0 10px 0 rgba(0,0,0,0.4) inset;
|
||||
}
|
||||
|
||||
.touch-dpad, .touch-buttons{
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.touch-buttons{
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.touch-dpad--up{
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Only show controls on portrait mode screens */
|
||||
@media screen and (min-aspect-ratio: 1/1) {
|
||||
.touch-controls{
|
||||
display: none;
|
||||
}
|
||||
#main {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-grow: 1;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
283
public/gfiles/gba/user_scripts/AudioGlueCode.js
Normal file
283
public/gfiles/gba/user_scripts/AudioGlueCode.js
Normal file
|
@ -0,0 +1,283 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2015 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GlueCodeMixer(playButton) {
|
||||
var parentObj = this;
|
||||
this.audio = new XAudioServer(2, this.sampleRate, 0, this.bufferAmount, null, function () {
|
||||
parentObj.checkHeartbeats();
|
||||
}, function () {
|
||||
parentObj.checkPostHeartbeats();
|
||||
}, 1, function () {
|
||||
//Disable audio in the callback here:
|
||||
parentObj.disableAudio();
|
||||
}, playButton);
|
||||
this.outputUnits = [];
|
||||
this.outputUnitsValid = [];
|
||||
this.initializeBuffer();
|
||||
}
|
||||
GlueCodeMixer.prototype.sampleRate = 44100;
|
||||
GlueCodeMixer.prototype.bufferAmount = 44100;
|
||||
GlueCodeMixer.prototype.channelCount = 2;
|
||||
GlueCodeMixer.prototype.initializeBuffer = function () {
|
||||
this.buffer = new AudioSimpleBuffer(this.channelCount,
|
||||
this.bufferAmount);
|
||||
}
|
||||
GlueCodeMixer.prototype.appendInput = function (inUnit) {
|
||||
if (this.audio) {
|
||||
for (var index = 0; index < this.outputUnits.length; index++) {
|
||||
if (!this.outputUnits[index]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.outputUnits[index] = inUnit;
|
||||
this.outputUnitsValid.push(inUnit);
|
||||
inUnit.registerStackPosition(index);
|
||||
}
|
||||
else if (typeof inUnit.errorCallback == "function") {
|
||||
inUnit.errorCallback();
|
||||
}
|
||||
}
|
||||
GlueCodeMixer.prototype.unregister = function (stackPosition) {
|
||||
this.outputUnits[stackPosition] = null;
|
||||
this.outputUnitsValid = [];
|
||||
for (var index = 0, length = this.outputUnits.length; index < length; ++index) {
|
||||
if (this.outputUnits[index]) {
|
||||
this.outputUnitsValid.push(this.outputUnits);
|
||||
}
|
||||
}
|
||||
}
|
||||
GlueCodeMixer.prototype.checkHeartbeats = function () {
|
||||
var inputCount = this.outputUnitsValid.length;
|
||||
for (var inputIndex = 0, output = 0; inputIndex < inputCount; ++inputIndex) {
|
||||
this.outputUnitsValid[inputIndex].heartBeatCallback();
|
||||
}
|
||||
}
|
||||
GlueCodeMixer.prototype.checkPostHeartbeats = function () {
|
||||
var inputCount = this.outputUnitsValid.length;
|
||||
for (var inputIndex = 0, output = 0; inputIndex < inputCount; ++inputIndex) {
|
||||
this.outputUnitsValid[inputIndex].postHeartBeatCallback();
|
||||
}
|
||||
}
|
||||
GlueCodeMixer.prototype.checkAudio = function () {
|
||||
if (this.audio) {
|
||||
var inputCount = this.outputUnitsValid.length;
|
||||
for (var inputIndex = 0, output = 0; inputIndex < inputCount; ++inputIndex) {
|
||||
this.outputUnitsValid[inputIndex].prepareShift();
|
||||
}
|
||||
for (var count = 0, requested = this.findLowestBufferCount(); count < requested; ++count) {
|
||||
for (var inputIndex = 0, output = 0; inputIndex < inputCount; ++inputIndex) {
|
||||
output += this.outputUnitsValid[inputIndex].shift();
|
||||
}
|
||||
this.buffer.push(output);
|
||||
}
|
||||
var bufferLength = this.buffer.count();
|
||||
this.audio.writeAudioNoCallback(this.buffer.buffer, bufferLength);
|
||||
this.buffer.reset();
|
||||
}
|
||||
}
|
||||
GlueCodeMixer.prototype.findLowestBufferCount = function () {
|
||||
var count = 0;
|
||||
for (var inputIndex = 0, inputCount = this.outputUnitsValid.length; inputIndex < inputCount; ++inputIndex) {
|
||||
var tempCount = this.outputUnitsValid[inputIndex].buffer.resampledSamplesLeft();
|
||||
if (tempCount > 0) {
|
||||
if (count > 0) {
|
||||
count = Math.min(count, tempCount);
|
||||
}
|
||||
else {
|
||||
count = tempCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Math.min(count, this.channelCount * this.bufferAmount);
|
||||
}
|
||||
GlueCodeMixer.prototype.disableAudio = function () {
|
||||
this.audio = null;
|
||||
}
|
||||
function GlueCodeMixerInput(mixer) {
|
||||
this.mixer = mixer;
|
||||
this.volume = 1;
|
||||
}
|
||||
GlueCodeMixerInput.prototype.initialize = function (channelCount, sampleRate, bufferAmount, heartBeatCallback, postHeartBeatCallback, errorCallback) {
|
||||
this.channelCount = channelCount;
|
||||
this.sampleRate = sampleRate;
|
||||
this.bufferAmount = bufferAmount;
|
||||
this.heartBeatCallback = heartBeatCallback;
|
||||
this.postHeartBeatCallback = postHeartBeatCallback;
|
||||
this.errorCallback = errorCallback;
|
||||
var oldBuffer = this.buffer;
|
||||
this.buffer = new AudioBufferWrapper(this.channelCount,
|
||||
this.mixer.channelCount,
|
||||
this.bufferAmount,
|
||||
this.sampleRate,
|
||||
this.mixer.sampleRate);
|
||||
if (oldBuffer) {
|
||||
//If re-using same mixer input node, copy old buffer contents into the new buffer:
|
||||
this.buffer.copyOld(oldBuffer);
|
||||
}
|
||||
}
|
||||
GlueCodeMixerInput.prototype.register = function () {
|
||||
this.mixer.appendInput(this);
|
||||
}
|
||||
GlueCodeMixerInput.prototype.setVolume = function (volume) {
|
||||
this.volume = Math.min(Math.max(volume, 0), 1);
|
||||
}
|
||||
GlueCodeMixerInput.prototype.prepareShift = function () {
|
||||
this.buffer.resampleRefill();
|
||||
}
|
||||
GlueCodeMixerInput.prototype.shift = function () {
|
||||
return this.buffer.shift() * this.volume;
|
||||
}
|
||||
GlueCodeMixerInput.prototype.push = function (buffer, start, end) {
|
||||
this.buffer.push(buffer, start, end);
|
||||
this.mixer.checkAudio();
|
||||
}
|
||||
GlueCodeMixerInput.prototype.pushDeferred = function (buffer, start, end) {
|
||||
this.buffer.push(buffer, start, end);
|
||||
}
|
||||
GlueCodeMixerInput.prototype.flush = function () {
|
||||
this.mixer.checkAudio();
|
||||
}
|
||||
GlueCodeMixerInput.prototype.remainingBuffer = function () {
|
||||
return this.buffer.remainingBuffer() + (Math.floor((this.mixer.audio.remainingBuffer() * this.sampleRate / this.mixer.sampleRate) / this.mixer.channelCount) * this.mixer.channelCount);
|
||||
}
|
||||
GlueCodeMixerInput.prototype.registerStackPosition = function (stackPosition) {
|
||||
this.stackPosition = stackPosition;
|
||||
}
|
||||
GlueCodeMixerInput.prototype.unregister = function () {
|
||||
this.mixer.unregister(this.stackPosition);
|
||||
}
|
||||
GlueCodeMixerInput.prototype.setBufferSpace = function (bufferAmount) {
|
||||
this.buffer.setBufferSpace(bufferAmount);
|
||||
}
|
||||
function AudioBufferWrapper(channelCount,
|
||||
mixerChannelCount,
|
||||
bufferAmount,
|
||||
sampleRate,
|
||||
mixerSampleRate) {
|
||||
this.channelCount = channelCount;
|
||||
this.mixerChannelCount = mixerChannelCount;
|
||||
this.bufferAmount = bufferAmount;
|
||||
this.sampleRate = sampleRate;
|
||||
this.mixerSampleRate = mixerSampleRate;
|
||||
this.initialize();
|
||||
}
|
||||
AudioBufferWrapper.prototype.initialize = function () {
|
||||
this.inBufferSize = this.bufferAmount * this.mixerChannelCount;
|
||||
this.inBuffer = getFloat32Array(this.inBufferSize);
|
||||
this.resampler = new Resampler(this.sampleRate, this.mixerSampleRate, this.mixerChannelCount, this.inBuffer);
|
||||
this.outBufferSize = this.resampler.outputBuffer.length;
|
||||
this.outBuffer = getFloat32Array(this.outBufferSize);
|
||||
this.inputOffset = 0;
|
||||
this.resampleBufferStart = 0;
|
||||
this.resampleBufferEnd = 0;
|
||||
}
|
||||
AudioBufferWrapper.prototype.copyOld = function (oldBuffer) {
|
||||
this.resampleRefill();
|
||||
while (oldBuffer.resampleBufferStart != oldBuffer.resampleBufferEnd) {
|
||||
this.outBuffer[this.resampleBufferEnd++] = oldBuffer.outBuffer[oldBuffer.resampleBufferStart++];
|
||||
if (this.resampleBufferEnd == this.outBufferSize) {
|
||||
this.resampleBufferEnd = 0;
|
||||
}
|
||||
if (this.resampleBufferStart == this.resampleBufferEnd) {
|
||||
this.resampleBufferStart += this.mixerChannelCount;
|
||||
if (this.resampleBufferStart == this.outBufferSize) {
|
||||
this.resampleBufferStart = 0;
|
||||
}
|
||||
}
|
||||
if (oldBuffer.resampleBufferStart == oldBuffer.outBufferSize) {
|
||||
oldBuffer.resampleBufferStart = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
AudioBufferWrapper.prototype.push = function (buffer, start, end) {
|
||||
var length = Math.min(buffer.length, end);
|
||||
if (this.channelCount < this.mixerChannelCount) {
|
||||
for (; start < length && this.inputOffset < this.inBufferSize;) {
|
||||
for (var index = this.channelCount; index < this.mixerChannelCount; ++index) {
|
||||
this.inBuffer[this.inputOffset++] = buffer[start];
|
||||
}
|
||||
for (index = 0; index < this.channelCount && start < length; ++index) {
|
||||
this.inBuffer[this.inputOffset++] = buffer[start++];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.channelCount == this.mixerChannelCount) {
|
||||
for (; start < length && this.inputOffset < this.inBufferSize;) {
|
||||
this.inBuffer[this.inputOffset++] = buffer[start++];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (; start < length && this.inputOffset < this.inBufferSize;) {
|
||||
for (index = 0; index < this.mixerChannelCount && start < length; ++index) {
|
||||
this.inBuffer[this.inputOffset++] = buffer[start++];
|
||||
}
|
||||
start += this.channelCount - this.mixerChannelCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
AudioBufferWrapper.prototype.shift = function () {
|
||||
var output = 0;
|
||||
if (this.resampleBufferStart != this.resampleBufferEnd) {
|
||||
output = this.outBuffer[this.resampleBufferStart++];
|
||||
if (this.resampleBufferStart == this.outBufferSize) {
|
||||
this.resampleBufferStart = 0;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
AudioBufferWrapper.prototype.resampleRefill = function () {
|
||||
if (this.inputOffset > 0) {
|
||||
//Resample a chunk of audio:
|
||||
var resampleLength = this.resampler.resampler(this.inputOffset);
|
||||
var resampledResult = this.resampler.outputBuffer;
|
||||
for (var index2 = 0; index2 < resampleLength;) {
|
||||
this.outBuffer[this.resampleBufferEnd++] = resampledResult[index2++];
|
||||
if (this.resampleBufferEnd == this.outBufferSize) {
|
||||
this.resampleBufferEnd = 0;
|
||||
}
|
||||
if (this.resampleBufferStart == this.resampleBufferEnd) {
|
||||
this.resampleBufferStart += this.mixerChannelCount;
|
||||
if (this.resampleBufferStart == this.outBufferSize) {
|
||||
this.resampleBufferStart = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.inputOffset = 0;
|
||||
}
|
||||
}
|
||||
AudioBufferWrapper.prototype.setBufferSpace = function (bufferAmount) {
|
||||
while (this.inputOffset < bufferAmount && this.inputOffset < this.inBufferSize) {
|
||||
this.inBuffer[this.inputOffset++] = 0;
|
||||
}
|
||||
}
|
||||
AudioBufferWrapper.prototype.remainingBuffer = function () {
|
||||
return (Math.floor((this.resampledSamplesLeft() * this.resampler.ratioWeight) / this.mixerChannelCount) * this.mixerChannelCount) + this.inputOffset;
|
||||
}
|
||||
AudioBufferWrapper.prototype.resampledSamplesLeft = function () {
|
||||
return ((this.resampleBufferStart <= this.resampleBufferEnd) ? 0 : this.outBufferSize) + this.resampleBufferEnd - this.resampleBufferStart;
|
||||
}
|
||||
function AudioSimpleBuffer(channelCount, bufferAmount) {
|
||||
this.channelCount = channelCount;
|
||||
this.bufferAmount = bufferAmount;
|
||||
this.outBufferSize = this.channelCount * this.bufferAmount;
|
||||
this.stackLength = 0;
|
||||
this.buffer = getFloat32Array(this.outBufferSize);
|
||||
}
|
||||
AudioSimpleBuffer.prototype.push = function (data) {
|
||||
if (this.stackLength < this.outBufferSize) {
|
||||
this.buffer[this.stackLength++] = data;
|
||||
}
|
||||
}
|
||||
AudioSimpleBuffer.prototype.count = function () {
|
||||
return this.stackLength;
|
||||
}
|
||||
AudioSimpleBuffer.prototype.reset = function () {
|
||||
this.stackLength = 0;
|
||||
}
|
178
public/gfiles/gba/user_scripts/CoreGlueCode.js
Normal file
178
public/gfiles/gba/user_scripts/CoreGlueCode.js
Normal file
|
@ -0,0 +1,178 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2019 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
var IodineGUI = {
|
||||
Iodine:null,
|
||||
Blitter:null,
|
||||
coreTimerID:null,
|
||||
GUITimerID: null,
|
||||
toMap:null,
|
||||
toMapIndice:0,
|
||||
suspended:false,
|
||||
isPlaying:false,
|
||||
startTime:(+(new Date()).getTime()),
|
||||
mixerInput:null,
|
||||
currentSpeed:[false,0],
|
||||
defaults:{
|
||||
timerRate:8,
|
||||
sound:true,
|
||||
volume:1,
|
||||
skipBoot:false,
|
||||
toggleSmoothScaling:true,
|
||||
toggleDynamicSpeed:false,
|
||||
toggleOffthreadGraphics:true,
|
||||
toggleOffthreadCPU:(navigator.userAgent.indexOf('AppleWebKit') == -1 || (navigator.userAgent.indexOf('Windows NT 10.0') != -1 && navigator.userAgent.indexOf('Trident') == -1)),
|
||||
keyZonesGBA:[
|
||||
//Use this to control the GBA key mapping:
|
||||
//A:
|
||||
68,
|
||||
//B:
|
||||
67,
|
||||
//Select:
|
||||
32,
|
||||
//Start:
|
||||
13,
|
||||
//Right:
|
||||
39,
|
||||
//Left:
|
||||
37,
|
||||
//Up:
|
||||
38,
|
||||
//Down:
|
||||
40,
|
||||
//R:
|
||||
88,
|
||||
//L:
|
||||
83
|
||||
//Why are these switched lol
|
||||
],
|
||||
keyZonesControl:[
|
||||
//Use this to control the emulator function key mapping:
|
||||
//Volume Down:
|
||||
55,
|
||||
//Volume Up:
|
||||
56,
|
||||
//Speed Up:
|
||||
52,
|
||||
//Slow Down:
|
||||
51,
|
||||
//Reset Speed:
|
||||
53,
|
||||
//Toggle Fullscreen:
|
||||
54,
|
||||
//Play/Pause:
|
||||
80,
|
||||
//Restart:
|
||||
82
|
||||
]
|
||||
}
|
||||
};
|
||||
window.onload = function () {
|
||||
//Populate settings:
|
||||
registerDefaultSettings();
|
||||
//Initialize Iodine:
|
||||
registerIodineHandler();
|
||||
//Initialize the timer:
|
||||
calculateTiming();
|
||||
//Initialize the graphics:
|
||||
registerBlitterHandler();
|
||||
//Initialize the audio:
|
||||
registerAudioHandler();
|
||||
//Register the save handler callbacks:
|
||||
registerSaveHandlers();
|
||||
//Register the GUI controls.
|
||||
registerGUIEvents();
|
||||
//Register GUI settings.
|
||||
registerGUISettings();
|
||||
//Additional things.
|
||||
IodineGUI.Iodine.toggleSkipBootROM(true);
|
||||
IodineGUI.Blitter.setSmoothScaling(false);
|
||||
//File things.
|
||||
fileThings();
|
||||
}
|
||||
|
||||
function registerIodineHandler() {
|
||||
try {
|
||||
/*
|
||||
We utilize SharedArrayBuffer and Atomics API,
|
||||
which browsers prior to 2016 do not support:
|
||||
*/
|
||||
if (typeof SharedArrayBuffer != "function" || typeof Atomics != "object") {
|
||||
throw null;
|
||||
}
|
||||
else if (!IodineGUI.defaults.toggleOffthreadCPU && IodineGUI.defaults.toggleOffthreadGraphics) {
|
||||
//Try starting Iodine normally, but initialize offthread gfx:
|
||||
IodineGUI.Iodine = new IodineGBAWorkerGfxShim();
|
||||
}
|
||||
else if (IodineGUI.defaults.toggleOffthreadGraphics) {
|
||||
//Try starting Iodine in a webworker:
|
||||
IodineGUI.Iodine = new IodineGBAWorkerShim();
|
||||
//In order for save on page unload, this needs to be done:
|
||||
addEvent("beforeunload", window, registerBeforeUnloadHandler);
|
||||
}
|
||||
else {
|
||||
throw null;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
//Otherwise just run on-thread:
|
||||
IodineGUI.Iodine = new GameBoyAdvanceEmulator();
|
||||
}
|
||||
}
|
||||
function registerBeforeUnloadHandler(e) {
|
||||
IodineGUI.Iodine.pause();
|
||||
if (e.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
return "IodineGBA needs to process your save data, leaving now may result in not saving current data.";
|
||||
}
|
||||
function initTimer() {
|
||||
IodineGUI.Iodine.setIntervalRate(+IodineGUI.defaults.timerRate);
|
||||
IodineGUI.coreTimerID = setInterval(function () {
|
||||
IodineGUI.Iodine.timerCallback(((+(new Date()).getTime()) - (+IodineGUI.startTime)) >>> 0);
|
||||
}, IodineGUI.defaults.timerRate | 0);
|
||||
}
|
||||
function calculateTiming() {
|
||||
IodineGUI.Iodine.setIntervalRate(+IodineGUI.defaults.timerRate);
|
||||
}
|
||||
function startTimer() {
|
||||
IodineGUI.coreTimerID = setInterval(function () {
|
||||
IodineGUI.Iodine.timerCallback(((+(new Date()).getTime()) - (+IodineGUI.startTime)) >>> 0);
|
||||
}, IodineGUI.defaults.timerRate | 0);
|
||||
}
|
||||
function updateTimer(newRate) {
|
||||
newRate = newRate | 0;
|
||||
if ((newRate | 0) != (IodineGUI.defaults.timerRate | 0)) {
|
||||
IodineGUI.defaults.timerRate = newRate | 0;
|
||||
IodineGUI.Iodine.setIntervalRate(+IodineGUI.defaults.timerRate);
|
||||
if (IodineGUI.isPlaying) {
|
||||
if (IodineGUI.coreTimerID) {
|
||||
clearInterval(IodineGUI.coreTimerID);
|
||||
}
|
||||
initTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
function registerBlitterHandler() {
|
||||
IodineGUI.Blitter = new GfxGlueCode(240, 160);
|
||||
IodineGUI.Blitter.attachCanvas(document.getElementById("emulator_target"));
|
||||
IodineGUI.Iodine.attachGraphicsFrameHandler(IodineGUI.Blitter);
|
||||
IodineGUI.Blitter.attachGfxPostCallback(function () {
|
||||
if (IodineGUI.currentSpeed[0]) {
|
||||
var speedDOM = document.getElementById("speed");
|
||||
speedDOM.textContent = "Speed: " + IodineGUI.currentSpeed[1] + "%";
|
||||
}
|
||||
});
|
||||
}
|
||||
function registerAudioHandler() {
|
||||
var Mixer = new GlueCodeMixer(document.getElementById("play"));
|
||||
IodineGUI.mixerInput = new GlueCodeMixerInput(Mixer);
|
||||
IodineGUI.Iodine.attachAudioHandler(IodineGUI.mixerInput);
|
||||
}
|
667
public/gfiles/gba/user_scripts/GUIGlueCode.js
Normal file
667
public/gfiles/gba/user_scripts/GUIGlueCode.js
Normal file
|
@ -0,0 +1,667 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2019 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function registerGUIEvents() {
|
||||
//Catch any play status changes:
|
||||
IodineGUI.Iodine.attachPlayStatusHandler(updatePlayButton);
|
||||
//Add DOM events:
|
||||
addEvent("keydown", document, keyDown);
|
||||
addEvent("keyup", document, keyUpPreprocess);
|
||||
addEvent("change", document.getElementById("rom_load"), fileLoadROM);
|
||||
addEvent("change", document.getElementById("bios_load"), fileLoadBIOS);
|
||||
addEvent("click", document.getElementById("play"), function (e) {
|
||||
IodineGUI.Iodine.play();
|
||||
});
|
||||
addEvent("click", document.getElementById("pause"), function (e) {
|
||||
IodineGUI.Iodine.pause();
|
||||
});
|
||||
addEvent("click", document.getElementById("restart"), function (e) {
|
||||
IodineGUI.Iodine.restart();
|
||||
});
|
||||
addEvent("click", document.getElementById("sound"), function () {
|
||||
setValue("sound", !!this.checked);
|
||||
if (this.checked) {
|
||||
IodineGUI.Iodine.enableAudio();
|
||||
}
|
||||
else {
|
||||
IodineGUI.Iodine.disableAudio();
|
||||
}
|
||||
});
|
||||
addEvent("click", document.getElementById("skip_boot"), function () {
|
||||
setValue("skipBoot", !!this.checked);
|
||||
IodineGUI.Iodine.toggleSkipBootROM(this.checked);
|
||||
});
|
||||
addEvent("click", document.getElementById("toggleDynamicSpeed"), function () {
|
||||
setValue("toggleDynamicSpeed", !!this.checked);
|
||||
IodineGUI.Iodine.toggleDynamicSpeed(this.checked);
|
||||
});
|
||||
addEvent("click", document.getElementById("offthread-gpu"), function () {
|
||||
setValue("toggleOffthreadGraphics", !!this.checked);
|
||||
IodineGUI.Iodine.toggleOffthreadGraphics(this.checked);
|
||||
});
|
||||
addEvent("click", document.getElementById("offthread-cpu"), function () {
|
||||
setValue("toggleOffthreadCPU", !!this.checked);
|
||||
//Can't do anything until reload of page.
|
||||
});
|
||||
addEvent("change", document.getElementById("speedset"), speedChangeFunc);
|
||||
addEvent("input", document.getElementById("speedset"), speedChangeFunc);
|
||||
addEvent("click", document.getElementById("fullscreen"), toggleFullScreen);
|
||||
addEvent("click", document.getElementById("key_a"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 0;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-a"), function () {
|
||||
IodineGUI.Iodine.keyDown(0);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-a"), function () {
|
||||
IodineGUI.Iodine.keyUp(0);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_b"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 1;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-b"), function () {
|
||||
IodineGUI.Iodine.keyDown(1);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-b"), function () {
|
||||
IodineGUI.Iodine.keyUp(1);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_select"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 2;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-select"), function () {
|
||||
IodineGUI.Iodine.keyDown(2);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-select"), function () {
|
||||
IodineGUI.Iodine.keyUp(2);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_start"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 3;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-start"), function () {
|
||||
IodineGUI.Iodine.keyDown(3);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-start"), function () {
|
||||
IodineGUI.Iodine.keyUp(3);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_right"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 4;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-right"), function () {
|
||||
IodineGUI.Iodine.keyDown(4);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-right"), function () {
|
||||
IodineGUI.Iodine.keyUp(4);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_left"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 5;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-left"), function () {
|
||||
IodineGUI.Iodine.keyDown(5);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-left"), function () {
|
||||
IodineGUI.Iodine.keyUp(5);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_up"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 6;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-up"), function () {
|
||||
IodineGUI.Iodine.keyDown(6);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-up"), function () {
|
||||
IodineGUI.Iodine.keyUp(6);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_down"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 7;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-down"), function () {
|
||||
IodineGUI.Iodine.keyDown(7);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-down"), function () {
|
||||
IodineGUI.Iodine.keyUp(7);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_r"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 8;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-r"), function () {
|
||||
IodineGUI.Iodine.keyDown(8);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-r"), function () {
|
||||
IodineGUI.Iodine.keyUp(8);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_l"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesGBA;
|
||||
IodineGUI.toMapIndice = 9;
|
||||
});
|
||||
addEvent("mousedown", document.getElementById("touch-l"), function () {
|
||||
IodineGUI.Iodine.keyDown(9);
|
||||
});
|
||||
addEvent("mouseup", document.getElementById("touch-l"), function () {
|
||||
IodineGUI.Iodine.keyUp(9);
|
||||
});
|
||||
addEvent("click", document.getElementById("key_volumedown"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesControl;
|
||||
IodineGUI.toMapIndice = 0;
|
||||
});
|
||||
addEvent("click", document.getElementById("key_volumeup"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesControl;
|
||||
IodineGUI.toMapIndice = 1;
|
||||
});
|
||||
addEvent("click", document.getElementById("key_speedup"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesControl;
|
||||
IodineGUI.toMapIndice = 2;
|
||||
});
|
||||
addEvent("click", document.getElementById("key_slowdown"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesControl;
|
||||
IodineGUI.toMapIndice = 3;
|
||||
});
|
||||
addEvent("click", document.getElementById("key_speedreset"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesControl;
|
||||
IodineGUI.toMapIndice = 4;
|
||||
});
|
||||
addEvent("click", document.getElementById("key_fullscreen"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesControl;
|
||||
IodineGUI.toMapIndice = 5;
|
||||
});
|
||||
addEvent("click", document.getElementById("key_playpause"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesControl;
|
||||
IodineGUI.toMapIndice = 6;
|
||||
});
|
||||
addEvent("click", document.getElementById("key_restart"), function () {
|
||||
IodineGUI.toMap = IodineGUI.defaults.keyZonesControl;
|
||||
IodineGUI.toMapIndice = 7;
|
||||
});
|
||||
addEvent("change", document.getElementById("import"), function (e) {
|
||||
if (typeof this.files != "undefined") {
|
||||
try {
|
||||
if (this.files.length >= 1) {
|
||||
writeRedTemporaryText("Reading the local file \"" + this.files[0].name + "\" for importing.");
|
||||
try {
|
||||
//Gecko 1.9.2+ (Standard Method)
|
||||
var binaryHandle = new FileReader();
|
||||
binaryHandle.onload = function () {
|
||||
if (this.readyState == 2) {
|
||||
writeRedTemporaryText("file imported.");
|
||||
try {
|
||||
import_save(this.result);
|
||||
}
|
||||
catch (error) {
|
||||
writeRedTemporaryText(error.message + " file: " + error.fileName + " line: " + error.lineNumber);
|
||||
}
|
||||
}
|
||||
else {
|
||||
writeRedTemporaryText("importing file, please wait...");
|
||||
}
|
||||
}
|
||||
binaryHandle.readAsBinaryString(this.files[this.files.length - 1]);
|
||||
}
|
||||
catch (error) {
|
||||
//Gecko 1.9.0, 1.9.1 (Non-Standard Method)
|
||||
var romImageString = this.files[this.files.length - 1].getAsBinary();
|
||||
try {
|
||||
import_save(romImageString);
|
||||
}
|
||||
catch (error) {
|
||||
writeRedTemporaryText(error.message + " file: " + error.fileName + " line: " + error.lineNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
writeRedTemporaryText("Incorrect number of files selected for local loading.");
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
writeRedTemporaryText("Could not load in a locally stored ROM file.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
writeRedTemporaryText("could not find the handle on the file to open.");
|
||||
}
|
||||
if (e.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
addEvent("click", document.getElementById("export"), refreshStorageListing);
|
||||
addEvent("unload", window, ExportSave);
|
||||
IodineGUI.Iodine.attachSpeedHandler(function (speed) {
|
||||
speed = speed.toFixed(2);
|
||||
if (speed != IodineGUI.currentSpeed[1]) {
|
||||
IodineGUI.currentSpeed[1] = speed;
|
||||
IodineGUI.currentSpeed[0] = true;
|
||||
}
|
||||
});
|
||||
addEvent("change", document.getElementById("volume"), volChangeFunc);
|
||||
addEvent("input", document.getElementById("volume"), volChangeFunc);
|
||||
addEvent("resize", window, resizeCanvasFunc);
|
||||
addEvent("mouseover", document.getElementById("saves_menu"), rebuildSavesMenu);
|
||||
if (typeof document.hidden !== "undefined") {
|
||||
addEvent("visibilitychange", document, visibilityChangeHandle);
|
||||
}
|
||||
else if (typeof document.mozHidden !== "undefined") {
|
||||
addEvent("mozvisibilitychange", document, mozVisibilityChangeHandle);
|
||||
}
|
||||
else if (typeof document.msHidden !== "undefined") {
|
||||
addEvent("msvisibilitychange", document, msVisibilityChangeHandle);
|
||||
}
|
||||
else if (typeof document.webkitHidden !== "undefined") {
|
||||
addEvent("webkitvisibilitychange", document, webkitVisibilityChangeHandle);
|
||||
}
|
||||
//Run on init as well:
|
||||
resizeCanvasFunc();
|
||||
}
|
||||
function registerDefaultSettings() {
|
||||
if (findValue("sound") === null) {
|
||||
setValue("sound", !!IodineGUI.defaults.sound);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.sound = !!findValue("sound");
|
||||
}
|
||||
if (findValue("volume") === null) {
|
||||
setValue("volume", +IodineGUI.defaults.volume);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.volume = +findValue("volume");
|
||||
}
|
||||
document.getElementById("volume").value = Math.round(IodineGUI.defaults.volume * 100);
|
||||
document.getElementById("speedset").value = 50;
|
||||
if (findValue("skipBoot") === null) {
|
||||
setValue("skipBoot", !!IodineGUI.defaults.skipBoot);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.skipBoot = !!findValue("skipBoot");
|
||||
}
|
||||
if (findValue("toggleSmoothScaling") === null) {
|
||||
setValue("toggleSmoothScaling", !!IodineGUI.defaults.toggleSmoothScaling);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.toggleSmoothScaling = !!findValue("toggleSmoothScaling");
|
||||
}
|
||||
if (findValue("toggleDynamicSpeed") === null) {
|
||||
setValue("toggleDynamicSpeed", !!IodineGUI.defaults.toggleDynamicSpeed);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.toggleDynamicSpeed = !!findValue("toggleDynamicSpeed");
|
||||
}
|
||||
if (findValue("toggleOffthreadGraphics") === null) {
|
||||
setValue("toggleOffthreadGraphics", !!IodineGUI.defaults.toggleOffthreadGraphics);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.toggleOffthreadGraphics = !!findValue("toggleOffthreadGraphics");
|
||||
}
|
||||
if (findValue("toggleOffthreadCPU") === null) {
|
||||
setValue("toggleOffthreadCPU", !!IodineGUI.defaults.toggleOffthreadCPU);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.toggleOffthreadCPU = !!findValue("toggleOffthreadCPU");
|
||||
}
|
||||
// Why is this even a thing???
|
||||
/*if (findValue("key_a") === null) {
|
||||
setValue("key_a", IodineGUI.defaults.keyZonesGBA[0] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[0] = findValue("key_a");
|
||||
}
|
||||
if (findValue("key_b") === null) {
|
||||
setValue("key_b", IodineGUI.defaults.keyZonesGBA[1] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[1] = findValue("key_b");
|
||||
}
|
||||
if (findValue("key_select") === null) {
|
||||
setValue("key_select", IodineGUI.defaults.keyZonesGBA[2] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[2] = findValue("key_select");
|
||||
}
|
||||
if (findValue("key_start") === null) {
|
||||
setValue("key_start", IodineGUI.defaults.keyZonesGBA[3] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[3] = findValue("key_start");
|
||||
}
|
||||
if (findValue("key_right") === null) {
|
||||
setValue("key_right", IodineGUI.defaults.keyZonesGBA[4] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[4] = findValue("key_right");
|
||||
}
|
||||
if (findValue("key_left") === null) {
|
||||
setValue("key_left", IodineGUI.defaults.keyZonesGBA[5] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[5] = findValue("key_left");
|
||||
}
|
||||
if (findValue("key_up") === null) {
|
||||
setValue("key_up", IodineGUI.defaults.keyZonesGBA[6] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[6] = findValue("key_up");
|
||||
}
|
||||
if (findValue("key_down") === null) {
|
||||
setValue("key_down", IodineGUI.defaults.keyZonesGBA[7] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[7] = findValue("key_down");
|
||||
}
|
||||
if (findValue("key_r") === null) {
|
||||
setValue("key_r", IodineGUI.defaults.keyZonesGBA[8] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[8] = findValue("key_r");
|
||||
}
|
||||
if (findValue("key_l") === null) {
|
||||
setValue("key_l", IodineGUI.defaults.keyZonesGBA[9] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesGBA[9] = findValue("key_l");
|
||||
}*/
|
||||
if (findValue("key_volumedown") === null) {
|
||||
setValue("key_volumedown", IodineGUI.defaults.keyZonesControl[0] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesControl[0] = findValue("key_volumedown");
|
||||
}
|
||||
if (findValue("key_volumeup") === null) {
|
||||
setValue("key_volumeup", IodineGUI.defaults.keyZonesControl[1] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesControl[1] = findValue("key_volumeup");
|
||||
}
|
||||
if (findValue("key_speedup") === null) {
|
||||
setValue("key_speedup", IodineGUI.defaults.keyZonesControl[2] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesControl[2] = findValue("key_speedup");
|
||||
}
|
||||
if (findValue("key_slowdown") === null) {
|
||||
setValue("key_slowdown", IodineGUI.defaults.keyZonesControl[3] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesControl[3] = findValue("key_slowdown");
|
||||
}
|
||||
if (findValue("key_speedreset") === null) {
|
||||
setValue("key_speedreset", IodineGUI.defaults.keyZonesControl[4] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesControl[4] = findValue("key_speedreset");
|
||||
}
|
||||
if (findValue("key_fullscreen") === null) {
|
||||
setValue("key_fullscreen", IodineGUI.defaults.keyZonesControl[5] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesControl[5] = findValue("key_fullscreen");
|
||||
}
|
||||
if (findValue("key_playpause") === null) {
|
||||
setValue("key_playpause", IodineGUI.defaults.keyZonesControl[6] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesControl[6] = findValue("key_playpause");
|
||||
}
|
||||
if (findValue("key_restart") === null) {
|
||||
setValue("key_restart", IodineGUI.defaults.keyZonesControl[7] | 0);
|
||||
}
|
||||
else {
|
||||
IodineGUI.defaults.keyZonesControl[7] = findValue("key_restart");
|
||||
}
|
||||
}
|
||||
function saveKeyBindings() {
|
||||
setValue("key_a", IodineGUI.defaults.keyZonesGBA[0] | 0);
|
||||
setValue("key_b", IodineGUI.defaults.keyZonesGBA[1] | 0);
|
||||
setValue("key_select", IodineGUI.defaults.keyZonesGBA[2] | 0);
|
||||
setValue("key_start", IodineGUI.defaults.keyZonesGBA[3] | 0);
|
||||
setValue("key_right", IodineGUI.defaults.keyZonesGBA[4] | 0);
|
||||
setValue("key_left", IodineGUI.defaults.keyZonesGBA[5] | 0);
|
||||
setValue("key_up", IodineGUI.defaults.keyZonesGBA[6] | 0);
|
||||
setValue("key_down", IodineGUI.defaults.keyZonesGBA[7] | 0);
|
||||
setValue("key_r", IodineGUI.defaults.keyZonesGBA[8] | 0);
|
||||
setValue("key_l", IodineGUI.defaults.keyZonesGBA[9] | 0);
|
||||
setValue("key_volumedown", IodineGUI.defaults.keyZonesControl[0] | 0);
|
||||
setValue("key_volumeup", IodineGUI.defaults.keyZonesControl[1] | 0);
|
||||
setValue("key_speedup", IodineGUI.defaults.keyZonesControl[2] | 0);
|
||||
setValue("key_slowdown", IodineGUI.defaults.keyZonesControl[3] | 0);
|
||||
setValue("key_speedreset", IodineGUI.defaults.keyZonesControl[4] | 0);
|
||||
setValue("key_fullscreen", IodineGUI.defaults.keyZonesControl[5] | 0);
|
||||
setValue("key_playpause", IodineGUI.defaults.keyZonesControl[6] | 0);
|
||||
setValue("key_restart", IodineGUI.defaults.keyZonesControl[7] | 0);
|
||||
}
|
||||
function registerGUISettings() {
|
||||
document.getElementById("sound").checked = IodineGUI.defaults.sound;
|
||||
if (IodineGUI.defaults.sound) {
|
||||
IodineGUI.Iodine.enableAudio();
|
||||
}
|
||||
try {
|
||||
var volControl = document.getElementById("volume");
|
||||
volControl.min = 0;
|
||||
volControl.max = 100;
|
||||
volControl.step = 1;
|
||||
volControl.value = IodineGUI.defaults.volume * 100;
|
||||
}
|
||||
catch (e) {}
|
||||
IodineGUI.mixerInput.setVolume(IodineGUI.defaults.volume);
|
||||
document.getElementById("skip_boot").checked = IodineGUI.defaults.skipBoot;
|
||||
IodineGUI.Iodine.toggleSkipBootROM(IodineGUI.defaults.skipBoot);
|
||||
document.getElementById("toggleSmoothScaling").checked = IodineGUI.defaults.toggleSmoothScaling;
|
||||
IodineGUI.Blitter.setSmoothScaling(IodineGUI.defaults.toggleSmoothScaling);
|
||||
document.getElementById("toggleDynamicSpeed").checked = IodineGUI.defaults.toggleDynamicSpeed;
|
||||
IodineGUI.Iodine.toggleDynamicSpeed(IodineGUI.defaults.toggleDynamicSpeed);
|
||||
document.getElementById("offthread-gpu").checked = IodineGUI.defaults.toggleOffthreadGraphics;
|
||||
IodineGUI.Iodine.toggleOffthreadGraphics(IodineGUI.defaults.toggleOffthreadGraphics);
|
||||
document.getElementById("offthread-cpu").checked = IodineGUI.defaults.toggleOffthreadCPU;
|
||||
if (typeof SharedArrayBuffer != "function" || typeof Atomics != "object") {
|
||||
document.getElementById("offthread-gpu").disabled = true;
|
||||
document.getElementById("offthread-cpu").disabled = true;
|
||||
}
|
||||
}
|
||||
function updatePlayButton(isPlaying) {
|
||||
isPlaying = isPlaying | 0;
|
||||
if ((isPlaying | 0) == 1) {
|
||||
document.getElementById("play").className = "hide";
|
||||
document.getElementById("pause").className = "show";
|
||||
document.getElementById("menu").className = "playing";
|
||||
if (!IodineGUI.coreTimerID) {
|
||||
startTimer();
|
||||
}
|
||||
IodineGUI.isPlaying = true;
|
||||
}
|
||||
else {
|
||||
document.getElementById("pause").className = "hide";
|
||||
document.getElementById("play").className = "show";
|
||||
document.getElementById("menu").className = "paused";
|
||||
if (IodineGUI.coreTimerID) {
|
||||
clearInterval(IodineGUI.coreTimerID);
|
||||
IodineGUI.coreTimerID = null;
|
||||
}
|
||||
IodineGUI.isPlaying = false;
|
||||
}
|
||||
}
|
||||
function visibilityChangeHandle() {
|
||||
processVisibilityChange(document.hidden);
|
||||
}
|
||||
function mozVisibilityChangeHandle() {
|
||||
processVisibilityChange(document.mozHidden);
|
||||
}
|
||||
function msVisibilityChangeHandle() {
|
||||
processVisibilityChange(document.msHidden);
|
||||
}
|
||||
function webkitVisibilityChangeHandle() {
|
||||
processVisibilityChange(document.webkitHidden);
|
||||
}
|
||||
function processVisibilityChange(isHidden) {
|
||||
if (!isHidden) {
|
||||
if (IodineGUI.suspended) {
|
||||
IodineGUI.suspended = false;
|
||||
IodineGUI.Iodine.play();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (document.getElementById("play").className == "hide") {
|
||||
IodineGUI.Iodine.pause();
|
||||
IodineGUI.suspended = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
function stepVolume(delta) {
|
||||
var volume = document.getElementById("volume").value / 100;
|
||||
volume = Math.min(Math.max(volume + delta, 0), 1);
|
||||
IodineGUI.mixerInput.setVolume(volume);
|
||||
document.getElementById("volume").value = Math.round(volume * 100);
|
||||
}
|
||||
function volChangeFunc() {
|
||||
var volume = Math.min(Math.max(parseInt(this.value), 0), 100) * 0.01;
|
||||
setValue("volume", +volume);
|
||||
IodineGUI.mixerInput.setVolume(+volume);
|
||||
};
|
||||
function speedChangeFunc() {
|
||||
var speed = Math.min(Math.max(parseInt(this.value), 0), 100) / 50;
|
||||
speed = speed * speed;
|
||||
IodineGUI.Iodine.setSpeed(+speed);
|
||||
}
|
||||
function writeRedTemporaryText(textString) {
|
||||
//lol
|
||||
/*if (IodineGUI.GUITimerID) {
|
||||
clearTimeout(IodineGUI.GUITimerID);
|
||||
}
|
||||
document.getElementById("tempMessage").style.display = "block";
|
||||
document.getElementById("tempMessage").textContent = textString;
|
||||
IodineGUI.GUITimerID = setTimeout(clearTempString, 5000);*/
|
||||
}
|
||||
function clearTempString() {
|
||||
document.getElementById("tempMessage").style.display = "none";
|
||||
}
|
||||
function resizeCanvasFunc() {
|
||||
var container = document.getElementById("main");
|
||||
var containerHeight = container.clientHeight || container.offsetHeight || 0;
|
||||
var containerWidth = container.clientWidth || container.offsetWidth || 0;
|
||||
if (containerHeight > 0 && containerWidth > 0) {
|
||||
var canvas = document.getElementById("emulator_target");
|
||||
var maxWidth = Math.floor(containerHeight * 1.5);
|
||||
var maxHeight = Math.floor(containerWidth / 1.5);
|
||||
var height = Math.min(maxHeight, containerHeight);
|
||||
var width = Math.min(maxWidth, containerWidth);
|
||||
canvas.style.width = width + "px";
|
||||
canvas.style.height = height + "px";
|
||||
}
|
||||
}
|
||||
function rebuildSavesMenu(e) {
|
||||
if (didNotEnter(document.getElementById("saves_menu_container"), e)) {
|
||||
ExportSave();
|
||||
rebuildExistingSaves();
|
||||
if (e.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
function rebuildExistingSaves() {
|
||||
var menu = document.getElementById("existing_saves_list");
|
||||
ExportSave();
|
||||
removeChildNodes(menu);
|
||||
var keys = getSavesKeys();
|
||||
while (keys.length > 0) {
|
||||
addExistingSaveItem(menu, keys.shift());
|
||||
}
|
||||
}
|
||||
function addExistingSaveItem(menu, key) {
|
||||
var listItem = document.createElement("li");
|
||||
listItem.className = "nowrap";
|
||||
var spanItem = document.createElement("span");
|
||||
spanItem.textContent = decodeKeyType(key);
|
||||
listItem.appendChild(spanItem);
|
||||
var submenu = document.createElement("ul");
|
||||
var submenuItem = document.createElement("li");
|
||||
submenuItem.className = "nowrap";
|
||||
addEvent("click", submenuItem, function () {
|
||||
deleteValue(key);
|
||||
rebuildExistingSaves();
|
||||
});
|
||||
var submenuSpan = document.createElement("span");
|
||||
submenuSpan.textContent = "Delete";
|
||||
submenuItem.appendChild(submenuSpan);
|
||||
submenu.appendChild(submenuItem);
|
||||
var submenuItem2 = document.createElement("li");
|
||||
submenuItem2.className = "nowrap";
|
||||
var link1 = document.createElement("a");
|
||||
link1.href = "data:application/octet-stream;base64," + base64(generateBlob(key, findValue(key)));
|
||||
link1.download = key + "_" + ((new Date()).getTime()) + ".export";
|
||||
link1.textContent = "Download as import compatible";
|
||||
submenuItem2.appendChild(link1);
|
||||
submenu.appendChild(submenuItem2);
|
||||
var submenuItem3 = document.createElement("li");
|
||||
submenuItem3.className = "nowrap";
|
||||
var link2 = document.createElement("a");
|
||||
//Saves are already encoded in base64:
|
||||
link2.href = "data:application/octet-stream;base64," + findValue(key);
|
||||
link2.download = key + "_" + ((new Date()).getTime()) + ".sav";
|
||||
link2.textContent = "Download as raw binary";
|
||||
submenuItem3.appendChild(link2);
|
||||
submenu.appendChild(submenuItem3);
|
||||
listItem.appendChild(submenu);
|
||||
menu.appendChild(listItem);
|
||||
}
|
||||
function decodeKeyType(key) {
|
||||
if (key.substring(0, 15) == "SAVE_TYPE_GUID_") {
|
||||
return "Game \"" + key.substring(15) + "\" Type Code";
|
||||
}
|
||||
else if (key.substring(0, 10) == "SAVE_GUID_") {
|
||||
return "Game \"" + key.substring(10) + "\" Cartridge Data";
|
||||
}
|
||||
else if (key.substring(0, 15) == "SAVE_RTC_GUID_") {
|
||||
return "Game \"" + key.substring(15) + "\" RTC Data";
|
||||
}
|
||||
return key;
|
||||
}
|
||||
//Some wrappers and extensions for non-DOM3 browsers:
|
||||
function removeChildNodes(node) {
|
||||
while (node.firstChild) {
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
}
|
||||
function didNotEnter(oElement, event) {
|
||||
var target = (typeof event.target != "undefined") ? event.target : event.srcElement;
|
||||
while (target) {
|
||||
if (isSameNode(target, oElement)) {
|
||||
return false;
|
||||
}
|
||||
target = target.parentElement;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function isSameNode(oCheck1, oCheck2) {
|
||||
return (typeof oCheck1.isSameNode == "function") ? oCheck1.isSameNode(oCheck2) : (oCheck1 === oCheck2);
|
||||
}
|
||||
function addEvent(sEvent, oElement, fListener) {
|
||||
try {
|
||||
oElement.addEventListener(sEvent, fListener, false);
|
||||
}
|
||||
catch (error) {
|
||||
oElement.attachEvent("on" + sEvent, fListener); //Pity for IE.
|
||||
}
|
||||
}
|
||||
function removeEvent(sEvent, oElement, fListener) {
|
||||
try {
|
||||
oElement.removeEventListener(sEvent, fListener, false);
|
||||
}
|
||||
catch (error) {
|
||||
oElement.detachEvent("on" + sEvent, fListener); //Pity for IE.
|
||||
}
|
||||
}
|
||||
|
||||
function setSmooth(){
|
||||
var chekd = document.getElementById("smooth").checked;setValue("toggleSmoothScaling", !!chekd);
|
||||
if (IodineGUI.Blitter) {
|
||||
IodineGUI.Blitter.setSmoothScaling(chekd);
|
||||
}
|
||||
}
|
209
public/gfiles/gba/user_scripts/GfxGlueCode.js
Normal file
209
public/gfiles/gba/user_scripts/GfxGlueCode.js
Normal file
|
@ -0,0 +1,209 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2010-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function GfxGlueCode(width, height) {
|
||||
this.graphicsFound = false; //Do we have graphics output sink found yet?
|
||||
this.gfxCallback = null; //Optional callback user-supplied for vsync eventing.
|
||||
this.doSmoothing = true; //Texture filter the framebuffer?
|
||||
this.offscreenWidth = width; //Width of the screen.
|
||||
this.offscreenHeight = height; //Height of the screen.
|
||||
this.offscreenRGBCount = this.offscreenWidth * this.offscreenHeight * 3;
|
||||
this.offscreenRGBACount = this.offscreenWidth * this.offscreenHeight * 4;
|
||||
this.initializeVSync(); //Setup the vsync event.
|
||||
this.initializeBuffers(); //Initialize the buffer storage.
|
||||
}
|
||||
GfxGlueCode.prototype.initializeVSync = function () {
|
||||
window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
|
||||
var parentObj = this;
|
||||
if (!window.requestAnimationFrame) {
|
||||
//Fallback timer eventing:
|
||||
setInterval(function () {
|
||||
parentObj.vsync();
|
||||
}, 16);
|
||||
}
|
||||
else {
|
||||
//Initialize the rAF eventing:
|
||||
window.requestAnimationFrame(
|
||||
function () {
|
||||
parentObj.vsync();
|
||||
parentObj.rAFKeepAlive();
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.rAFKeepAlive = function () {
|
||||
//Keep the vsync event requested:
|
||||
var parentObj = this;
|
||||
window.requestAnimationFrame(function () {
|
||||
parentObj.vsync();
|
||||
parentObj.rAFKeepAlive();
|
||||
});
|
||||
}
|
||||
GfxGlueCode.prototype.attachCanvas = function (canvas) {
|
||||
this.canvas = canvas;
|
||||
this.graphicsFound = this.initializeCanvasTarget();
|
||||
}
|
||||
GfxGlueCode.prototype.detachCanvas = function () {
|
||||
this.canvas = null;
|
||||
}
|
||||
GfxGlueCode.prototype.attachGfxCallback = function (gfxCallback) {
|
||||
if (typeof gfxCallback == "function") {
|
||||
this.gfxCallback = gfxCallback;
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.attachGfxPostCallback = function (gfxPostCallback) {
|
||||
if (typeof gfxPostCallback == "function") {
|
||||
this.gfxPostCallback = gfxPostCallback;
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.vsync = function () {
|
||||
if (this.graphicsFound) {
|
||||
if (typeof this.gfxCallback == "function") {
|
||||
//Let the user supplied code prepare a frame or two:
|
||||
this.gfxCallback();
|
||||
}
|
||||
//Draw a frame, if ready:
|
||||
this.requestDraw();
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.initializeBuffers = function () {
|
||||
this.swizzledFrameFree = [getUint8Array(this.offscreenRGBCount), getUint8Array(this.offscreenRGBCount)];
|
||||
this.swizzledFrameReady = [];
|
||||
}
|
||||
GfxGlueCode.prototype.recomputeDimension = function () {
|
||||
//Cache some dimension info:
|
||||
this.canvasLastWidth = this.canvas.clientWidth;
|
||||
this.canvasLastHeight = this.canvas.clientHeight;
|
||||
if ((navigator.userAgent.toLowerCase().indexOf("gecko") != -1 && navigator.userAgent.toLowerCase().indexOf("like gecko") == -1)) { //Sniff out firefox for selecting this path.
|
||||
//Set target as unscaled:
|
||||
this.onscreenWidth = this.canvas.width = this.offscreenWidth;
|
||||
this.onscreenHeight = this.canvas.height = this.offscreenHeight;
|
||||
}
|
||||
else {
|
||||
//Set target canvas as scaled:
|
||||
this.onscreenWidth = this.canvas.width = this.canvas.clientWidth;
|
||||
this.onscreenHeight = this.canvas.height = this.canvas.clientHeight;
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.initializeCanvasTarget = function () {
|
||||
try {
|
||||
//Obtain dimensional information:
|
||||
this.recomputeDimension();
|
||||
//Get handles on the canvases:
|
||||
this.canvasOffscreen = document.createElement("canvas");
|
||||
this.canvasOffscreen.width = this.offscreenWidth;
|
||||
this.canvasOffscreen.height = this.offscreenHeight;
|
||||
this.drawContextOffscreen = this.canvasOffscreen.getContext("2d");
|
||||
this.drawContextOnscreen = this.canvas.getContext("2d");
|
||||
//Initialize the canvas backing buffer:
|
||||
this.initializeCanvasBuffer();
|
||||
//Success:
|
||||
return true;
|
||||
}
|
||||
catch (error) {
|
||||
//Failure:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.initializeCanvasBuffer = function () {
|
||||
//Get a CanvasPixelArray buffer:
|
||||
this.canvasBuffer = this.getBuffer(this.drawContextOffscreen, this.offscreenWidth, this.offscreenHeight);
|
||||
//Initialize Alpha Channel:
|
||||
this.initializeAlpha(this.canvasBuffer.data);
|
||||
}
|
||||
GfxGlueCode.prototype.initializeAlpha = function (canvasData) {
|
||||
var length = canvasData.length;
|
||||
for (var indexGFXIterate = 3; indexGFXIterate < length; indexGFXIterate += 4) {
|
||||
canvasData[indexGFXIterate] = 0xFF;
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.getBuffer = function (canvasContext, width, height) {
|
||||
//Get a CanvasPixelArray buffer:
|
||||
var buffer = null;
|
||||
try {
|
||||
buffer = this.drawContextOffscreen.createImageData(width, height);
|
||||
}
|
||||
catch (error) {
|
||||
buffer = this.drawContextOffscreen.getImageData(0, 0, width, height);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
if (__VIEWS_SUPPORTED__) {
|
||||
GfxGlueCode.prototype.copyBuffer = function (buffer) {
|
||||
if (this.graphicsFound) {
|
||||
if (this.swizzledFrameFree.length == 0) {
|
||||
this.swizzledFrameFree.push(this.swizzledFrameReady.shift());
|
||||
}
|
||||
var swizzledFrame = this.swizzledFrameFree.shift();
|
||||
swizzledFrame.set(buffer);
|
||||
this.swizzledFrameReady.push(swizzledFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
GfxGlueCode.prototype.copyBuffer = function (buffer) {
|
||||
if (this.graphicsFound) {
|
||||
if (this.swizzledFrameFree.length == 0) {
|
||||
this.swizzledFrameFree.push(this.swizzledFrameReady.shift());
|
||||
}
|
||||
var swizzledFrame = this.swizzledFrameFree.shift();
|
||||
for (var bufferIndex = 0; bufferIndex < this.offscreenRGBCount; bufferIndex++) {
|
||||
swizzledFrame[bufferIndex] = buffer[bufferIndex];
|
||||
}
|
||||
this.swizzledFrameReady.push(swizzledFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.requestDraw = function () {
|
||||
if (this.swizzledFrameReady.length > 0) {
|
||||
var canvasData = this.canvasBuffer.data;
|
||||
var swizzledFrame = this.swizzledFrameReady.shift();
|
||||
for (var canvasIndex = 0, bufferIndex = 0; canvasIndex < this.offscreenRGBACount; ++canvasIndex) {
|
||||
canvasData[canvasIndex++] = swizzledFrame[bufferIndex++];
|
||||
canvasData[canvasIndex++] = swizzledFrame[bufferIndex++];
|
||||
canvasData[canvasIndex++] = swizzledFrame[bufferIndex++];
|
||||
}
|
||||
this.swizzledFrameFree.push(swizzledFrame);
|
||||
this.graphicsBlit();
|
||||
if (typeof this.gfxPostCallback == "function") {
|
||||
//Some UI element redraw:
|
||||
this.gfxPostCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.graphicsBlit = function () {
|
||||
if (this.canvasLastWidth != this.canvas.clientWidth || this.canvasLastHeight != this.canvas.clientHeight) {
|
||||
this.recomputeDimension();
|
||||
this.processSmoothing();
|
||||
}
|
||||
if (this.offscreenWidth == this.onscreenWidth && this.offscreenHeight == this.onscreenHeight) {
|
||||
//Canvas does not need to scale, draw directly to final:
|
||||
this.drawContextOnscreen.putImageData(this.canvasBuffer, 0, 0);
|
||||
}
|
||||
else {
|
||||
//Canvas needs to scale, draw to offscreen first:
|
||||
this.drawContextOffscreen.putImageData(this.canvasBuffer, 0, 0);
|
||||
//Scale offscreen canvas image onto the final:
|
||||
this.drawContextOnscreen.drawImage(this.canvasOffscreen, 0, 0, this.onscreenWidth, this.onscreenHeight);
|
||||
}
|
||||
}
|
||||
GfxGlueCode.prototype.setSmoothScaling = function (doSmoothing) {
|
||||
this.doSmoothing = !!doSmoothing;
|
||||
this.processSmoothing();
|
||||
}
|
||||
GfxGlueCode.prototype.processSmoothing = function () {
|
||||
if (this.graphicsFound) {
|
||||
this.canvas.className = (this.doSmoothing) ? "textureSmooth" : "texturePixelated";
|
||||
this.drawContextOnscreen.mozImageSmoothingEnabled = this.doSmoothing;
|
||||
this.drawContextOnscreen.webkitImageSmoothingEnabled = this.doSmoothing;
|
||||
this.drawContextOnscreen.imageSmoothingEnabled = this.doSmoothing;
|
||||
}
|
||||
}
|
124
public/gfiles/gba/user_scripts/JoyPadGlueCode.js
Normal file
124
public/gfiles/gba/user_scripts/JoyPadGlueCode.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function keyDown(e) {
|
||||
var keyCode = e.keyCode | 0;
|
||||
for (var keyMapIndex = 0; (keyMapIndex | 0) < 10; keyMapIndex = ((keyMapIndex | 0) + 1) | 0) {
|
||||
if ((IodineGUI.defaults.keyZonesGBA[keyMapIndex | 0] | 0) == (keyCode | 0)) {
|
||||
IodineGUI.Iodine.keyDown(keyMapIndex | 0);
|
||||
if (e.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function keyUpGBA(keyCode) {
|
||||
keyCode = keyCode | 0;
|
||||
for (var keyMapIndex = 0; (keyMapIndex | 0) < 10; keyMapIndex = ((keyMapIndex | 0) + 1) | 0) {
|
||||
if ((IodineGUI.defaults.keyZonesGBA[keyMapIndex | 0] | 0) == (keyCode | 0)) {
|
||||
IodineGUI.Iodine.keyUp(keyMapIndex | 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function keyUp(keyCode) {
|
||||
keyCode = keyCode | 0;
|
||||
for (var keyMapIndex = 0; (keyMapIndex | 0) < 8; keyMapIndex = ((keyMapIndex | 0) + 1) | 0) {
|
||||
if ((IodineGUI.defaults.keyZonesControl[keyMapIndex | 0] | 0) == (keyCode | 0)) {
|
||||
keyboardEmulatorControl(keyMapIndex | 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function keyUpPreprocess(e) {
|
||||
var keyCode = e.keyCode | 0;
|
||||
//If we're not mapping a key:
|
||||
if (!IodineGUI.toMap) {
|
||||
//Check for emulator binding:
|
||||
if (!keyUp(keyCode | 0)) {
|
||||
//Check for GBA binding:
|
||||
keyUpGBA(keyCode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Map a key binding:
|
||||
IodineGUI.toMap[IodineGUI.toMapIndice | 0] = keyCode | 0;
|
||||
IodineGUI.toMap = null;
|
||||
saveKeyBindings();
|
||||
}
|
||||
}
|
||||
function keyboardEmulatorControl(keyCode) {
|
||||
keyCode = keyCode | 0;
|
||||
switch (keyCode | 0) {
|
||||
case 0:
|
||||
stepVolume(-0.04);
|
||||
break;
|
||||
case 1:
|
||||
stepVolume(0.04);
|
||||
break;
|
||||
case 2:
|
||||
IodineGUI.Iodine.incrementSpeed(0.05);
|
||||
break;
|
||||
case 3:
|
||||
IodineGUI.Iodine.incrementSpeed(-0.05);
|
||||
break;
|
||||
case 4:
|
||||
IodineGUI.Iodine.setSpeed(1);
|
||||
break;
|
||||
case 5:
|
||||
toggleFullScreen();
|
||||
break;
|
||||
case 6:
|
||||
togglePlayState();
|
||||
break;
|
||||
case 7:
|
||||
IodineGUI.Iodine.restart();
|
||||
}
|
||||
}
|
||||
function toggleFullScreen() {
|
||||
if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement ) {
|
||||
if (document.documentElement.requestFullscreen) {
|
||||
document.documentElement.requestFullscreen();
|
||||
}
|
||||
else if (document.documentElement.msRequestFullscreen) {
|
||||
document.documentElement.msRequestFullscreen();
|
||||
}
|
||||
else if (document.documentElement.mozRequestFullScreen) {
|
||||
document.documentElement.mozRequestFullScreen();
|
||||
}
|
||||
else if (document.documentElement.webkitRequestFullscreen) {
|
||||
document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen();
|
||||
}
|
||||
else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
}
|
||||
else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen();
|
||||
}
|
||||
}
|
||||
}
|
||||
function togglePlayState() {
|
||||
if (IodineGUI.isPlaying) {
|
||||
IodineGUI.Iodine.pause();
|
||||
}
|
||||
else {
|
||||
IodineGUI.Iodine.play();
|
||||
}
|
||||
}
|
115
public/gfiles/gba/user_scripts/ROMLoadGlueCode.js
Normal file
115
public/gfiles/gba/user_scripts/ROMLoadGlueCode.js
Normal file
|
@ -0,0 +1,115 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2016 Grant Galitz
|
||||
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.
|
||||
*/
|
||||
function fileThings() {
|
||||
if(window.location.hash){
|
||||
downloadBIOS();
|
||||
downloadROM();
|
||||
} else {
|
||||
document.getElementById('ffd').style.display = "block";
|
||||
downloadBIOS();
|
||||
}
|
||||
}
|
||||
function yayPlay() {
|
||||
document.getElementById("play").click();
|
||||
}
|
||||
function gba_upload(upload) {
|
||||
document.getElementById('ffd').style.display = "none";
|
||||
fileLoadShimCode(upload.files, attachROM);
|
||||
}
|
||||
function downloadBIOS() {
|
||||
downloadFile("bios.bin", "BIOS");
|
||||
}
|
||||
function downloadROM() {
|
||||
var romloc = "./roms/" + window.location.hash.substring(1) + ".gba";
|
||||
downloadFile(romloc, "ROM");
|
||||
}
|
||||
function attachBIOS(BIOS) {
|
||||
try {
|
||||
IodineGUI.Iodine.attachBIOS(new Uint8Array(BIOS));
|
||||
}
|
||||
catch (error) {
|
||||
IodineGUI.Iodine.attachBIOS(BIOS);
|
||||
}
|
||||
}
|
||||
function attachROM(ROM) {
|
||||
try {
|
||||
IodineGUI.Iodine.attachROM(new Uint8Array(ROM));
|
||||
}
|
||||
catch (error) {
|
||||
IodineGUI.Iodine.attachROM(ROM);
|
||||
}
|
||||
}
|
||||
function fileLoadShimCode(files, ROMHandler) {
|
||||
if (typeof files != "undefined") {
|
||||
if (files.length >= 1) {
|
||||
//Gecko 1.9.2+ (Standard Method)
|
||||
try {
|
||||
var binaryHandle = new FileReader();
|
||||
binaryHandle.onloadend = function () {
|
||||
ROMHandler(this.result);
|
||||
yayPlay();
|
||||
}
|
||||
binaryHandle.readAsArrayBuffer(files[files.length - 1]);
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
var result = files[files.length - 1].getAsBinary();
|
||||
var resultConverted = [];
|
||||
for (var index = 0; index < result.length; ++index) {
|
||||
resultConverted[index] = result.charCodeAt(index) & 0xFF;
|
||||
}
|
||||
ROMHandler(resultConverted);
|
||||
yayPlay();
|
||||
}
|
||||
catch (error) {
|
||||
alert("Could not load the processed ROM file!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function fileLoadBIOS() {
|
||||
fileLoadShimCode(this.files, attachBIOS);
|
||||
}
|
||||
function fileLoadROM() {
|
||||
fileLoadShimCode(this.files, attachROM);
|
||||
}
|
||||
function downloadFile(fileName, reg) {
|
||||
var ajax = new XMLHttpRequest();
|
||||
ajax.onload = function(){
|
||||
if(ajax.status=="404"){
|
||||
document.getElementById('ffd').style.display = "block";
|
||||
alert("Could not find " + fileName.substring(2));
|
||||
} else {
|
||||
if(reg=="BIOS"){
|
||||
processDownload(this, attachBIOS);
|
||||
} else if(reg=="ROM"){
|
||||
processDownload(this, attachROM);
|
||||
yayPlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
ajax.open("GET", "./" + fileName, true);
|
||||
ajax.responseType = "arraybuffer";
|
||||
ajax.overrideMimeType("text/plain; charset=x-user-defined");
|
||||
ajax.send(null);
|
||||
}
|
||||
function processDownload(parentObj, attachHandler) {
|
||||
try {
|
||||
attachHandler(new Uint8Array(parentObj.response));
|
||||
}
|
||||
catch (error) {
|
||||
var data = parentObj.responseText;
|
||||
var length = data.length;
|
||||
var dataArray = [];
|
||||
for (var index = 0; index < length; index++) {
|
||||
dataArray[index] = data.charCodeAt(index) & 0xFF;
|
||||
}
|
||||
attachHandler(dataArray);
|
||||
}
|
||||
}
|
289
public/gfiles/gba/user_scripts/SavesGlueCode.js
Normal file
289
public/gfiles/gba/user_scripts/SavesGlueCode.js
Normal file
|
@ -0,0 +1,289 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2010-2017 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function ImportSaveCallback(name, callbackFunc, callbackFuncNoSave) {
|
||||
try {
|
||||
var save = findValue("SAVE_" + name);
|
||||
if (save != null) {
|
||||
writeRedTemporaryText("Loaded save.");
|
||||
callbackFunc(base64ToArray(save));
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
writeRedTemporaryText("Could not read save: " + error.message);
|
||||
}
|
||||
callbackFuncNoSave();
|
||||
}
|
||||
function ExportSave() {
|
||||
IodineGUI.Iodine.exportSave();
|
||||
}
|
||||
function ExportSaveCallback(name, save) {
|
||||
if (name != "") {
|
||||
try {
|
||||
setValue("SAVE_" + name, arrayToBase64(save));
|
||||
}
|
||||
catch (error) {
|
||||
writeRedTemporaryText("Could not store save: " + error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
function registerSaveHandlers() {
|
||||
IodineGUI.Iodine.attachSaveExportHandler(ExportSaveCallback);
|
||||
IodineGUI.Iodine.attachSaveImportHandler(ImportSaveCallback);
|
||||
}
|
||||
function import_save(blobData) {
|
||||
blobData = decodeBlob(blobData);
|
||||
if (blobData && blobData.blobs) {
|
||||
if (blobData.blobs.length > 0) {
|
||||
for (var index = 0; index < blobData.blobs.length; ++index) {
|
||||
var blobID = blobData.blobs[index].blobID;
|
||||
var blobContent = blobData.blobs[index].blobContent;
|
||||
writeRedTemporaryText("Importing blob \"" + blobID + "\"");
|
||||
if (blobContent) {
|
||||
setValue(blobID, blobContent);
|
||||
}
|
||||
else if (blobID) {
|
||||
writeRedTemporaryText("Save file imported had blob \"" + blobID + "\" with no blob data interpretable.");
|
||||
}
|
||||
else {
|
||||
writeRedTemporaryText("Blob chunk information missing completely.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
writeRedTemporaryText("Could not decode the imported file.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
writeRedTemporaryText("Could not decode the imported file.");
|
||||
}
|
||||
}
|
||||
function generateBlob(keyName, encodedData) {
|
||||
//Append the file format prefix:
|
||||
var saveString = "EMULATOR_DATA";
|
||||
var consoleID = "GameBoyAdvance";
|
||||
//Figure out the length:
|
||||
var totalLength = (saveString.length + 4 + (1 + consoleID.length)) + ((1 + keyName.length) + (4 + encodedData.length));
|
||||
//Append the total length in bytes:
|
||||
saveString += to_little_endian_word(totalLength);
|
||||
//Append the console ID text's length:
|
||||
saveString += to_byte(consoleID.length);
|
||||
//Append the console ID text:
|
||||
saveString += consoleID;
|
||||
//Append the blob ID:
|
||||
saveString += to_byte(keyName.length);
|
||||
saveString += keyName;
|
||||
//Now append the save data:
|
||||
saveString += to_little_endian_word(encodedData.length);
|
||||
saveString += encodedData;
|
||||
return saveString;
|
||||
}
|
||||
function generateMultiBlob(blobPairs) {
|
||||
var consoleID = "GameBoyAdvance";
|
||||
//Figure out the initial length:
|
||||
var totalLength = 13 + 4 + 1 + consoleID.length;
|
||||
//Append the console ID text's length:
|
||||
var saveString = to_byte(consoleID.length);
|
||||
//Append the console ID text:
|
||||
saveString += consoleID;
|
||||
var keyName = "";
|
||||
var encodedData = "";
|
||||
//Now append all the blobs:
|
||||
for (var index = 0; index < blobPairs.length; ++index) {
|
||||
keyName = blobPairs[index][0];
|
||||
encodedData = blobPairs[index][1];
|
||||
//Append the blob ID:
|
||||
saveString += to_byte(keyName.length);
|
||||
saveString += keyName;
|
||||
//Now append the save data:
|
||||
saveString += to_little_endian_word(encodedData.length);
|
||||
saveString += encodedData;
|
||||
//Update the total length:
|
||||
totalLength += 1 + keyName.length + 4 + encodedData.length;
|
||||
}
|
||||
//Now add the prefix:
|
||||
saveString = "EMULATOR_DATA" + to_little_endian_word(totalLength) + saveString;
|
||||
return saveString;
|
||||
}
|
||||
function decodeBlob(blobData) {
|
||||
/*Format is as follows:
|
||||
- 13 byte string "EMULATOR_DATA"
|
||||
- 4 byte total size (including these 4 bytes).
|
||||
- 1 byte Console type ID length
|
||||
- Console type ID text of 8 bit size
|
||||
blobs {
|
||||
- 1 byte blob ID length
|
||||
- blob ID text (Used to say what the data is (SRAM/freeze state/etc...))
|
||||
- 4 byte blob length
|
||||
- blob of 32 bit length size
|
||||
- Blob itself is encoded in base64.
|
||||
}
|
||||
*/
|
||||
var length = blobData.length;
|
||||
var blobProperties = {};
|
||||
blobProperties.consoleID = null;
|
||||
var blobsCount = -1;
|
||||
blobProperties.blobs = [];
|
||||
if (length > 17) {
|
||||
if (blobData.substring(0, 13) == "EMULATOR_DATA") {
|
||||
var length = Math.min(((blobData.charCodeAt(16) & 0xFF) << 24) | ((blobData.charCodeAt(15) & 0xFF) << 16) | ((blobData.charCodeAt(14) & 0xFF) << 8) | (blobData.charCodeAt(13) & 0xFF), length);
|
||||
var consoleIDLength = blobData.charCodeAt(17) & 0xFF;
|
||||
if (length > 17 + consoleIDLength) {
|
||||
blobProperties.consoleID = blobData.substring(18, 18 + consoleIDLength);
|
||||
var blobIDLength = 0;
|
||||
var blobLength = 0;
|
||||
for (var index = 18 + consoleIDLength; index < length;) {
|
||||
blobIDLength = blobData.charCodeAt(index++) & 0xFF;
|
||||
if (index + blobIDLength < length) {
|
||||
blobProperties.blobs[++blobsCount] = {};
|
||||
blobProperties.blobs[blobsCount].blobID = blobData.substring(index, index + blobIDLength);
|
||||
index += blobIDLength;
|
||||
if (index + 4 < length) {
|
||||
blobLength = ((blobData.charCodeAt(index + 3) & 0xFF) << 24) | ((blobData.charCodeAt(index + 2) & 0xFF) << 16) | ((blobData.charCodeAt(index + 1) & 0xFF) << 8) | (blobData.charCodeAt(index) & 0xFF);
|
||||
index += 4;
|
||||
if (index + blobLength <= length) {
|
||||
blobProperties.blobs[blobsCount].blobContent = blobData.substring(index, index + blobLength);
|
||||
index += blobLength;
|
||||
}
|
||||
else {
|
||||
writeRedTemporaryText("Blob length check failed, blob determined to be incomplete.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
writeRedTemporaryText("Blob was incomplete, bailing out.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
writeRedTemporaryText("Blob was incomplete, bailing out.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return blobProperties;
|
||||
}
|
||||
function refreshStorageListing() {
|
||||
var keys = getSavesKeys();
|
||||
var blobPairs = [];
|
||||
for (var index = 0; index < keys.length; ++index) {
|
||||
blobPairs[index] = [keys[index], findValue(keys[index])];
|
||||
}
|
||||
this.href = "data:application/octet-stream;base64," + base64(generateMultiBlob(blobPairs));
|
||||
this.download = "gameboy_advance_saves_" + ((new Date()).getTime()) + ".export";
|
||||
}
|
||||
function checkStorageLength() {
|
||||
try {
|
||||
if (window.localStorage) {
|
||||
return window.localStorage.length;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
//An older Gecko 1.8.1/1.9.0 method of storage (Deprecated due to the obvious security hole):
|
||||
if (window.globalStorage && location.hostname) {
|
||||
return window.globalStorage[location.hostname].length;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
function getSavesKeys() {
|
||||
var storageLength = checkStorageLength();
|
||||
var keysFound = [];
|
||||
var index = 0;
|
||||
var nextKey = null;
|
||||
while (index < storageLength) {
|
||||
nextKey = findKey(index++);
|
||||
if (nextKey !== null && nextKey.length > 0) {
|
||||
if (nextKey.substring(0, 15) == "IodineGBA_SAVE_") {
|
||||
keysFound.push(nextKey.substring(10));
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return keysFound;
|
||||
}
|
||||
function findKey(keyNum) {
|
||||
try {
|
||||
if (window.localStorage) {
|
||||
return window.localStorage.key(keyNum);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
//An older Gecko 1.8.1/1.9.0 method of storage (Deprecated due to the obvious security hole):
|
||||
if (window.globalStorage && location.hostname) {
|
||||
return window.globalStorage[location.hostname].key(keyNum);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function to_little_endian_word(str) {
|
||||
return to_little_endian_hword(str) + to_little_endian_hword(str >> 16);
|
||||
}
|
||||
function to_little_endian_hword(str) {
|
||||
return to_byte(str) + to_byte(str >> 8);
|
||||
}
|
||||
function to_byte(str) {
|
||||
return String.fromCharCode(str & 0xFF);
|
||||
}
|
||||
//Wrapper for localStorage getItem, so that data can be retrieved in various types.
|
||||
function findValue(key) {
|
||||
key = "IodineGBA_" + key;
|
||||
try {
|
||||
if (window.localStorage) {
|
||||
if (window.localStorage.getItem(key) != null) {
|
||||
return JSON.parse(window.localStorage.getItem(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
//An older Gecko 1.8.1/1.9.0 method of storage (Deprecated due to the obvious security hole):
|
||||
if (window.globalStorage && location.hostname) {
|
||||
if (window.globalStorage[location.hostname].getItem(key) != null) {
|
||||
return JSON.parse(window.globalStorage[location.hostname].getItem(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//Wrapper for localStorage setItem, so that data can be set in various types.
|
||||
function setValue(key, value) {
|
||||
key = "IodineGBA_" + key;
|
||||
try {
|
||||
if (window.localStorage) {
|
||||
window.localStorage.setItem(key, JSON.stringify(value));
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
//An older Gecko 1.8.1/1.9.0 method of storage (Deprecated due to the obvious security hole):
|
||||
if (window.globalStorage && location.hostname) {
|
||||
window.globalStorage[location.hostname].setItem(key, JSON.stringify(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
//Wrapper for localStorage removeItem, so that data can be set in various types.
|
||||
function deleteValue(key) {
|
||||
key = "IodineGBA_" + key;
|
||||
try {
|
||||
if (window.localStorage) {
|
||||
window.localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
//An older Gecko 1.8.1/1.9.0 method of storage (Deprecated due to the obvious security hole):
|
||||
if (window.globalStorage && location.hostname) {
|
||||
window.globalStorage[location.hostname].removeItem(key);
|
||||
}
|
||||
}
|
||||
}
|
130
public/gfiles/gba/user_scripts/WorkerGfxGlueCode.js
Normal file
130
public/gfiles/gba/user_scripts/WorkerGfxGlueCode.js
Normal file
|
@ -0,0 +1,130 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2019 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
var gfxBuffers = null;
|
||||
var gfxCounters = null;
|
||||
function IodineGBAWorkerGfxShim() {
|
||||
this.gfx = null;
|
||||
gfxBuffers = [getSharedUint8Array(160 * 240 * 3),
|
||||
getSharedUint8Array(160 * 240 * 3)];
|
||||
gfxCounters = getSharedInt32Array(3);
|
||||
this.Iodine = new GameBoyAdvanceEmulator();
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.play = function () {
|
||||
this.Iodine.play();
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.pause = function () {
|
||||
this.Iodine.pause();
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.restart = function () {
|
||||
this.Iodine.restart();
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.setIntervalRate = function (rate) {
|
||||
rate = +rate;
|
||||
this.Iodine.setIntervalRate(+rate);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.timerCallback = function (timestamp) {
|
||||
timestamp = timestamp >>> 0;
|
||||
this.Iodine.timerCallback(timestamp);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.attachGraphicsFrameHandler = function (gfx) {
|
||||
this.gfx = gfx;
|
||||
var parentObj = this;
|
||||
this.gfx.attachGfxCallback(function () {
|
||||
parentObj.graphicsHeartBeat();
|
||||
});
|
||||
this.Iodine.attachGraphicsFrameHandler(gfx);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.attachAudioHandler = function (audio) {
|
||||
this.Iodine.attachAudioHandler(audio);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.enableAudio = function () {
|
||||
this.Iodine.enableAudio();
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.disableAudio = function () {
|
||||
this.Iodine.disableAudio();
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.toggleSkipBootROM = function (doEnable) {
|
||||
doEnable = doEnable | 0;
|
||||
this.Iodine.toggleSkipBootROM(doEnable | 0);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.toggleDynamicSpeed = function (doEnable) {
|
||||
doEnable = doEnable | 0;
|
||||
this.Iodine.toggleDynamicSpeed(doEnable | 0);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.toggleOffthreadGraphics = function (doEnable) {
|
||||
doEnable = doEnable | 0;
|
||||
this.Iodine.toggleOffthreadGraphics(doEnable | 0);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.attachSpeedHandler = function (speed) {
|
||||
this.Iodine.attachSpeedHandler(speed);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.attachPlayStatusHandler = function (playStatus) {
|
||||
this.Iodine.attachPlayStatusHandler(playStatus);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.keyDown = function (keyCode) {
|
||||
keyCode = keyCode | 0;
|
||||
this.Iodine.keyDown(keyCode | 0);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.keyUp = function (keyCode) {
|
||||
keyCode = keyCode | 0;
|
||||
this.Iodine.keyUp(keyCode | 0);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.incrementSpeed = function (newSpeed) {
|
||||
newSpeed = +newSpeed;
|
||||
this.Iodine.incrementSpeed(+newSpeed);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.setSpeed = function (newSpeed) {
|
||||
newSpeed = +newSpeed;
|
||||
this.Iodine.setSpeed(+newSpeed);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.attachBIOS = function (BIOS) {
|
||||
this.Iodine.attachBIOS(BIOS);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.attachROM = function (ROM) {
|
||||
this.Iodine.attachROM(ROM);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.exportSave = function () {
|
||||
this.Iodine.exportSave();
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.attachSaveExportHandler = function (saveExport) {
|
||||
this.Iodine.attachSaveExportHandler(saveExport);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.attachSaveImportHandler = function (saveImport) {
|
||||
this.Iodine.attachSaveImportHandler(saveImport);
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.graphicsHeartBeat = function () {
|
||||
//If graphics callback handle provided and we got a buffer reference:
|
||||
if (this.gfx && gfxCounters) {
|
||||
//Copy the buffer out to local:
|
||||
this.consumeGraphicsBuffer();
|
||||
//Wake up the producer thread:
|
||||
Atomics.notify(gfxCounters, 2, 1);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerGfxShim.prototype.consumeGraphicsBuffer = function () {
|
||||
//Load the counter values:
|
||||
var start = gfxCounters[0] | 0; //Written by this thread.
|
||||
var end = Atomics.load(gfxCounters, 1) | 0; //Written by the other thread.
|
||||
//Don't process if nothing to process:
|
||||
if ((end | 0) == (start | 0)) {
|
||||
//Buffer is empty:
|
||||
return;
|
||||
}
|
||||
//Copy samples out from the ring buffer:
|
||||
do {
|
||||
//Hardcoded for 2 buffers for a triple buffer effect:
|
||||
this.gfx.copyBuffer(gfxBuffers[start & 0x1]);
|
||||
start = ((start | 0) + 1) | 0;
|
||||
} while ((start | 0) != (end | 0));
|
||||
//Update the starting position counter to match the end position:
|
||||
//Let the other Atomic loads/stores naturally flush this value:
|
||||
gfxCounters[0] = end | 0;
|
||||
}
|
328
public/gfiles/gba/user_scripts/WorkerGlueCode.js
Normal file
328
public/gfiles/gba/user_scripts/WorkerGlueCode.js
Normal file
|
@ -0,0 +1,328 @@
|
|||
"use strict";
|
||||
/*
|
||||
Copyright (C) 2012-2019 Grant Galitz
|
||||
|
||||
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.
|
||||
*/
|
||||
function IodineGBAWorkerShim() {
|
||||
this.playStatus = null;
|
||||
this.gfx = null;
|
||||
this.audio = null;
|
||||
this.speed = null;
|
||||
this.saveExport = null;
|
||||
this.saveImport = null;
|
||||
this.worker = null;
|
||||
this.gfxBuffers = null;
|
||||
this.gfxCounters = null;
|
||||
this.audioBuffer = null;
|
||||
this.audioCounters = null;
|
||||
this.audioSamplesRemaining = null;
|
||||
this.audioBufferSize = 0;
|
||||
this.audioBufferSizeMask = 0;
|
||||
this.audioInitialized = false;
|
||||
this.timestamp = null;
|
||||
this.initialize();
|
||||
}
|
||||
var tempvar = document.getElementsByTagName("script");
|
||||
IodineGBAWorkerShim.prototype.filepath = tempvar[tempvar.length-1].src;
|
||||
IodineGBAWorkerShim.prototype.initialize = function () {
|
||||
var parentObj = this;
|
||||
var loc = this.filepath.split("/");
|
||||
loc = loc.slice(0, loc.length - 2).join("/");
|
||||
loc += "/IodineGBA/core/Worker.js";
|
||||
this.worker = new Worker(loc);
|
||||
this.worker.onmessage = function (event) {
|
||||
parentObj.decodeMessage(event.data);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.sendMessageSingle = function (eventCode) {
|
||||
eventCode = eventCode | 0;
|
||||
this.worker.postMessage({messageID:eventCode});
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.sendMessageDouble = function (eventCode, eventData) {
|
||||
eventCode = eventCode | 0;
|
||||
this.worker.postMessage({messageID:eventCode, payload:eventData});
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.play = function () {
|
||||
this.sendMessageSingle(0);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.pause = function () {
|
||||
this.sendMessageSingle(1);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.restart = function () {
|
||||
this.sendMessageSingle(2);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.setIntervalRate = function (rate) {
|
||||
rate = +rate;
|
||||
this.sendMessageDouble(3, +rate);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.timerCallback = function (timestamp) {
|
||||
timestamp = timestamp >>> 0;
|
||||
//If memory location provided for timestamp buffering:
|
||||
if (this.timestamp) {
|
||||
//Forward latest timestamp to worker:
|
||||
Atomics.store(this.timestamp, 0, timestamp >>> 0);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.attachPlayStatusHandler = function (playStatus) {
|
||||
this.playStatus = playStatus;
|
||||
this.sendMessageSingle(23);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.issuePlayStatus = function (isPlaying) {
|
||||
isPlaying = isPlaying | 0;
|
||||
if (this.playStatus) {
|
||||
this.playStatus(isPlaying | 0);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.attachGraphicsFrameHandler = function (gfx) {
|
||||
this.gfx = gfx;
|
||||
var parentObj = this;
|
||||
this.gfx.attachGfxCallback(function () {
|
||||
parentObj.graphicsHeartBeat();
|
||||
});
|
||||
this.sendMessageSingle(4);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.attachAudioHandler = function (audio) {
|
||||
this.audio = audio;
|
||||
this.sendMessageSingle(5);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.enableAudio = function () {
|
||||
if (this.audio) {
|
||||
this.sendMessageSingle(6);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.disableAudio = function () {
|
||||
if (this.audio) {
|
||||
this.sendMessageSingle(7);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.toggleSkipBootROM = function (doEnable) {
|
||||
doEnable = doEnable | 0;
|
||||
this.sendMessageDouble(8, doEnable | 0);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.toggleDynamicSpeed = function (doEnable) {
|
||||
doEnable = doEnable | 0;
|
||||
this.sendMessageDouble(9, doEnable | 0);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.toggleOffthreadGraphics = function (doEnable) {
|
||||
doEnable = doEnable | 0;
|
||||
this.sendMessageDouble(22, doEnable | 0);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.attachSpeedHandler = function (speed) {
|
||||
this.speed = speed;
|
||||
this.sendMessageSingle(10);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.keyDown = function (keyCode) {
|
||||
keyCode = keyCode | 0;
|
||||
this.sendMessageDouble(11, keyCode | 0);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.keyUp = function (keyCode) {
|
||||
keyCode = keyCode | 0;
|
||||
this.sendMessageDouble(12, keyCode | 0);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.incrementSpeed = function (newSpeed) {
|
||||
newSpeed = +newSpeed;
|
||||
this.sendMessageDouble(13, +newSpeed);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.setSpeed = function (newSpeed) {
|
||||
newSpeed = +newSpeed;
|
||||
this.sendMessageDouble(14, +newSpeed);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.attachBIOS = function (BIOS) {
|
||||
this.sendMessageDouble(15, BIOS);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.attachROM = function (ROM) {
|
||||
this.sendMessageDouble(16, ROM);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.exportSave = function () {
|
||||
this.sendMessageSingle(17);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.attachSaveExportHandler = function (saveExport) {
|
||||
this.saveExport = saveExport;
|
||||
this.sendMessageSingle(18);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.attachSaveImportHandler = function (saveImport) {
|
||||
this.saveImport = saveImport;
|
||||
this.sendMessageSingle(19);
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.decodeMessage = function (data) {
|
||||
switch (data.messageID | 0) {
|
||||
case 0:
|
||||
this.buffersInitialize(data.gfxBuffer1, data.gfxBuffer2, data.gfxCounters, data.audioSamplesRemaining, data.timestamp);
|
||||
break;
|
||||
case 1:
|
||||
this.audioInitialize(data.channels | 0, +data.sampleRate, data.bufferLimit | 0, data.audioBuffer, data.audioCounters);
|
||||
break;
|
||||
case 2:
|
||||
this.audioRegister();
|
||||
break;
|
||||
case 3:
|
||||
this.audioUnregister();
|
||||
break;
|
||||
case 4:
|
||||
this.audioSetBufferSpace(data.audioBufferContainAmount | 0);
|
||||
break;
|
||||
case 5:
|
||||
this.saveImportRequest(data.saveID);
|
||||
break;
|
||||
case 6:
|
||||
this.saveExportRequest(data.saveID, data.saveData);
|
||||
break;
|
||||
case 7:
|
||||
this.speedPush(+data.speed);
|
||||
break;
|
||||
default:
|
||||
this.issuePlayStatus(data.playing | 0);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.audioInitialize = function (channels, sampleRate, bufferLimit, audioBuffer, audioCounters) {
|
||||
channels = channels | 0;
|
||||
sampleRate = +sampleRate;
|
||||
bufferLimit = bufferLimit | 0;
|
||||
var parentObj = this;
|
||||
if (this.audio) {
|
||||
//(Re-)Initialize:
|
||||
this.audio.initialize(channels | 0, +sampleRate, bufferLimit | 0, function () {
|
||||
//Empty buffers inside the provided audio event callback:
|
||||
parentObj.audioHeartBeat();
|
||||
}, function () {
|
||||
//Get the remaining sample count:
|
||||
parentObj.audioPostHeartBeat();
|
||||
},function () {
|
||||
//Disable audio in the callback here:
|
||||
parentObj.disableAudio();
|
||||
});
|
||||
this.audioInitialized = true;
|
||||
}
|
||||
//Grab the new buffer:
|
||||
this.audioBuffer = audioBuffer;
|
||||
this.audioCounters = audioCounters;
|
||||
this.audioBufferSize = audioBuffer.length | 0;
|
||||
this.audioBufferSizeMask = ((this.audioBufferSize | 0) - 1) | 0;
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.audioHeartBeat = function () {
|
||||
//If audio API handle provided and we got a buffer reference:
|
||||
if (this.audioInitialized) {
|
||||
//Empty the buffer out:
|
||||
this.consumeAudioBuffer();
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.consumeAudioBuffer = function () {
|
||||
//Load the counter values:
|
||||
var start = this.audioCounters[0] | 0; //Written by this thread.
|
||||
var end = Atomics.load(this.audioCounters, 1) | 0; //Written to by the other thread.
|
||||
//Don't process if nothing to process:
|
||||
if ((end | 0) == (start | 0)) {
|
||||
//Buffer is empty:
|
||||
return;
|
||||
}
|
||||
//Copy samples out from the ring buffer:
|
||||
this.copyAudioBuffer(start | 0, end | 0);
|
||||
//Update the sample count reported by the audio mixer:
|
||||
//Done before updating ring buffer counter, so we don't over-produce:
|
||||
this.audioPostHeartBeat();
|
||||
//Update the starting position counter to match the end position:
|
||||
//Atomic store, because the sample count by the audio system needs to be reported prior to this:
|
||||
Atomics.store(this.audioCounters, 0, end | 0);
|
||||
//Tell audio mixer input to flush to audio mixer:
|
||||
this.audio.flush();
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.copyAudioBuffer = function (start, end) {
|
||||
start = start | 0;
|
||||
end = end | 0;
|
||||
//Compute the positions in the ring buffer:
|
||||
var startCorrected = ((start | 0) & (this.audioBufferSizeMask | 0)) | 0;
|
||||
var endCorrected = ((end | 0) & (this.audioBufferSizeMask | 0)) | 0;
|
||||
//Copy samples out to audio mixer input (but don't process them yet):
|
||||
if ((startCorrected | 0) >= (endCorrected | 0)) {
|
||||
//Handle looping to start of buffer:
|
||||
this.audio.pushDeferred(this.audioBuffer, startCorrected | 0, this.audioBufferSize | 0);
|
||||
this.audio.pushDeferred(this.audioBuffer, 0, endCorrected | 0);
|
||||
}
|
||||
else {
|
||||
this.audio.pushDeferred(this.audioBuffer, startCorrected | 0, endCorrected | 0);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.audioPostHeartBeat = function () {
|
||||
//Push latest audio metrics with no buffering:
|
||||
this.audioSamplesRemaining[0] = this.audio.remainingBuffer() | 0;
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.graphicsHeartBeat = function () {
|
||||
//If graphics callback handle provided and we got a buffer reference:
|
||||
if (this.gfx && this.gfxCounters) {
|
||||
//Copy the buffer out to local:
|
||||
this.consumeGraphicsBuffer();
|
||||
//Wake up the producer thread:
|
||||
Atomics.notify(this.gfxCounters, 2, 1);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.consumeGraphicsBuffer = function () {
|
||||
//Load the counter values:
|
||||
var start = this.gfxCounters[0] | 0; //Written by this thread.
|
||||
var end = Atomics.load(this.gfxCounters, 1) | 0; //Written by the other thread.
|
||||
//Don't process if nothing to process:
|
||||
if ((end | 0) == (start | 0)) {
|
||||
//Buffer is empty:
|
||||
return;
|
||||
}
|
||||
//Copy samples out from the ring buffer:
|
||||
do {
|
||||
//Hardcoded for 2 buffers for a triple buffer effect:
|
||||
this.gfx.copyBuffer(this.gfxBuffers[start & 0x1]);
|
||||
start = ((start | 0) + 1) | 0;
|
||||
} while ((start | 0) != (end | 0));
|
||||
//Update the starting position counter to match the end position:
|
||||
//Let the other Atomic loads/stores naturally flush this value:
|
||||
this.gfxCounters[0] = end | 0;
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.audioRegister = function () {
|
||||
if (this.audio) {
|
||||
this.audio.register();
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.audioUnregister = function () {
|
||||
if (this.audio) {
|
||||
//Empty the existing buffer:
|
||||
this.audioHeartBeat();
|
||||
//Unregister from mixer:
|
||||
this.audio.unregister();
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.audioSetBufferSpace = function (bufferSpace) {
|
||||
bufferSpace = bufferSpace | 0;
|
||||
if (this.audio) {
|
||||
this.audio.setBufferSpace(bufferSpace | 0);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.buffersInitialize = function (gfxBuffer1, gfxBuffer2, gfxCounters, audioSamplesRemaining, timestamp) {
|
||||
this.gfxBuffers = [gfxBuffer1, gfxBuffer2];
|
||||
this.gfxCounters = gfxCounters;
|
||||
this.audioSamplesRemaining = audioSamplesRemaining;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.speedPush = function (speed) {
|
||||
speed = +speed;
|
||||
if (this.speed) {
|
||||
this.speed(+speed);
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.saveImportRequest = function (saveID) {
|
||||
if (this.saveImport) {
|
||||
var parentObj = this;
|
||||
this.saveImport(saveID, function (saveData) {
|
||||
parentObj.sendMessageDouble(20, saveData);
|
||||
},
|
||||
function () {
|
||||
parentObj.sendMessageSingle(21);
|
||||
});
|
||||
}
|
||||
}
|
||||
IodineGBAWorkerShim.prototype.saveExportRequest = function (saveID, saveData) {
|
||||
if (this.saveExport) {
|
||||
this.saveExport(saveID, saveData);
|
||||
}
|
||||
}
|
71
public/gfiles/gba/user_scripts/XAudioJS/README.md
Normal file
71
public/gfiles/gba/user_scripts/XAudioJS/README.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
<h1>XAudioJS</h1>
|
||||
<h3>A minimal cross-browser API for writing PCM audio samples:</h3>
|
||||
<p>This simple JavaScript library abstracts the push-for-audio API of Mozilla Audio, and the passive callback API of Web Audio.
|
||||
This library introduces an abstraction layer that provides a push-for-audio and a callback API in one. We even provide a flash fallback to bring us to a total of 3 APIs supported.</p>
|
||||
<br>
|
||||
<b>This software is hereby placed in the public domain for anyone to use.</b>
|
||||
<br>
|
||||
<h3>How To Initialize:</h3>
|
||||
<dl>
|
||||
<dt>new XAudioServer(int channels, double sampleRate, int bufferLow, int bufferHigh, function underRunCallback, function heartbeatCallback, function postheartbeatCallback, double volume, function failureCallback, object userEventLatch);</dt>
|
||||
<dd>Make sure only one instance of XAudioServer is running at any time.</dd>
|
||||
<dd>bufferLow MUST be less than bufferHigh.</dd>
|
||||
<dd>bufferHigh sets the internal FIFO buffer length for all APIs except the Mozilla Audio Data API. Overfill on FIFO causes the oldest samples to be dropped first.</dd>
|
||||
<dd>
|
||||
<h4>Array underRunCallback (int samplesRequested)</h4>
|
||||
<blockquote>
|
||||
Arguments: Passed the number of samples that are needed to replenish the internal audio buffer back to bufferLow.<br><br>
|
||||
Functionality: JS developer set callback that can pass back any number of samples to replenish the audio buffer with.<br><br>
|
||||
Return: Array of samples to be passed into the underlying audio buffer. MUST be divisible by number of channels used (Whole frames required.). The return array length DOES NOT NEED to be of length samplesRequested.
|
||||
</blockquote>
|
||||
</dd>
|
||||
<dd>
|
||||
<h4>void heartbeatCallback (void)</h4>
|
||||
<blockquote>
|
||||
Functionality: JS developers set this callback as a way to program against an audio clock, firing inside an audio event.
|
||||
</blockquote>
|
||||
</dd>
|
||||
<dd>
|
||||
<h4>void postheartbeatCallback (void)</h4>
|
||||
<blockquote>
|
||||
Functionality: JS developers set this callback as a way to program against an audio clock, firing immediately after an audio event.
|
||||
</blockquote>
|
||||
</dd>
|
||||
<dd>volume is the output volume.</dd>
|
||||
<dd>
|
||||
<h4>void failureCallback (void)</h4>
|
||||
<blockquote>
|
||||
Functionality: JS developers set this callback to handle no audio support being available from the browser.
|
||||
</blockquote>
|
||||
</dd>
|
||||
<dd>
|
||||
<h4>object userEventLatch</h4>
|
||||
<blockquote>
|
||||
Functionality: JS developers set this DOM object for the Web Audio API to enable audio from.
|
||||
</blockquote>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Function Reference:</h3>
|
||||
<dl>
|
||||
<dt>void writeAudio (Array buffer, Integer upTo)</dt>
|
||||
<dd>Arguments: Pass an array of audio samples that is divisible by the number of audio channels utilized (buffer % channels == 0), and an integer length delimiter that follows the same restriction.</dd>
|
||||
<dd>Functionality: Passes the audio samples directly into the underlying audio subsystem, <b>and can call the specified sample buffer under-run callback as needed (Does the equivalent of executeCallback in addition to the forced sample input.)<b>.</dd>
|
||||
<dd>Return: void (None).</dd>
|
||||
<dt>void writeAudioNoCallback (Array buffer, Integer upTo)</dt>
|
||||
<dd>Arguments: Pass an array of audio samples that is divisible by the number of audio channels utilized (buffer % channels == 0), and an integer length delimiter that follows the same restriction.</dd>
|
||||
<dd>Functionality: Passes the audio samples directly into the underlying audio subsystem.</dd>
|
||||
<dd>Return: void (None).</dd>
|
||||
<dt>int remainingBuffer (void)</dt>
|
||||
<dd>Arguments: void (None).</dd>
|
||||
<dd>Functionality: Returns the number of samples left in the audio system before running out of playable samples.</dd>
|
||||
<dd>Return (On valid): int samples_remaining (<b>CAN BE NEGATIVE<b>)</dd>
|
||||
<dd>Return (On invalid): null</dd>
|
||||
<dt>void executeCallback (void)</dt>
|
||||
<dd>Arguments: void (None).</dd>
|
||||
<dd>Functionality: Executes the audio sample under-run callback if the samples remaining is below the set buffer low limit.</dd>
|
||||
<dd>Return: void (None).</dd>
|
||||
<dt>void changeVolume (double volume)</dt>
|
||||
<dd>Arguments: double float between 0 and 1 specifying the volume.</dd>
|
||||
<dd>Functionality: Changes the volume. Will affect samples in buffer, so has a low-latency effect (Use this to do a fast-mute).</dd>
|
||||
<dd>Return: void (None).</dd>
|
||||
</dl>
|
86
public/gfiles/gba/user_scripts/XAudioJS/XAudioJS.as
Normal file
86
public/gfiles/gba/user_scripts/XAudioJS/XAudioJS.as
Normal file
|
@ -0,0 +1,86 @@
|
|||
package {
|
||||
import flash.media.Sound;
|
||||
import flash.events.SampleDataEvent;
|
||||
import flash.display.Sprite;
|
||||
import flash.external.ExternalInterface;
|
||||
public class XAudioJS extends Sprite {
|
||||
public var sound:Sound = null;
|
||||
public var channelBuffer:Vector.<Number> = new Vector.<Number>(8192, true);
|
||||
public var channels:int = 0;
|
||||
public var volume:Number = 0;
|
||||
public var samplesFound:int = 0;
|
||||
public function XAudioJS() {
|
||||
ExternalInterface.addCallback('initialize', initialize);
|
||||
ExternalInterface.addCallback('changeVolume', changeVolume);
|
||||
}
|
||||
//Initialization function for the flash backend of XAudioJS:
|
||||
public function initialize(channels:Number, newVolume:Number):void {
|
||||
//Initialize the new settings:
|
||||
this.channels = (int(channels) == 2) ? 2 : 1;
|
||||
this.changeVolume(newVolume);
|
||||
this.checkForSound();
|
||||
}
|
||||
//Volume changing function for the flash backend of XAudioJS:
|
||||
public function changeVolume(newVolume:Number):void {
|
||||
//Set the new volume:
|
||||
this.volume = Math.min(Math.max(newVolume, 0), 1);
|
||||
}
|
||||
//Calls the JavaScript function responsible for the polyfill:
|
||||
public function requestSamples():Boolean {
|
||||
//Call the javascript callback function:
|
||||
var buffer:String = ExternalInterface.call("XAudioJSFlashAudioEvent");
|
||||
//If we received an appropriate response:
|
||||
if (buffer !== null) {
|
||||
if ((buffer.length % this.channels) == 0) { //Outsmart bad programmers from messing us up. :/
|
||||
var channelSample:Number = 0;
|
||||
this.samplesFound = Math.min(buffer.length, 4096 * this.channels);
|
||||
for (var index:int = 0; index < this.samplesFound; ++index) {
|
||||
//Get the unsigned 15-bit encoded sample value at +0x3000 offset:
|
||||
channelSample = buffer.charCodeAt(index);
|
||||
//Range-check the sample frame value and convert it:
|
||||
this.channelBuffer[index] = (channelSample >= 0x3000 && channelSample < 0xAFFF) ? (this.volume * (((channelSample - 0x3000) / 0x3FFF) - 1)) : 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//Check to make sure the audio stream is enabled:
|
||||
public function checkForSound():void {
|
||||
if (this.sound == null) {
|
||||
this.sound = new Sound();
|
||||
this.sound.addEventListener(
|
||||
SampleDataEvent.SAMPLE_DATA,
|
||||
soundCallback
|
||||
);
|
||||
this.sound.play();
|
||||
}
|
||||
}
|
||||
//Flash Audio Refill Callback
|
||||
public function soundCallback(e:SampleDataEvent):void {
|
||||
var index:int = 0;
|
||||
if (this.requestSamples()) {
|
||||
if (this.channels == 2) {
|
||||
//Stereo:
|
||||
while (index < this.samplesFound) {
|
||||
e.data.writeFloat(this.channelBuffer[index++]);
|
||||
e.data.writeFloat(this.channelBuffer[index++]);
|
||||
}
|
||||
index >>= 1;
|
||||
}
|
||||
else {
|
||||
//Mono:
|
||||
while (index < this.samplesFound) {
|
||||
e.data.writeFloat(this.channelBuffer[index]);
|
||||
e.data.writeFloat(this.channelBuffer[index++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Write some silence if not enough samples are found:
|
||||
while (++index <= 2048) {
|
||||
e.data.writeFloat(0);
|
||||
e.data.writeFloat(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
BIN
public/gfiles/gba/user_scripts/XAudioJS/XAudioJS.swf
Normal file
BIN
public/gfiles/gba/user_scripts/XAudioJS/XAudioJS.swf
Normal file
Binary file not shown.
530
public/gfiles/gba/user_scripts/XAudioJS/XAudioServer.js
Normal file
530
public/gfiles/gba/user_scripts/XAudioJS/XAudioServer.js
Normal file
|
@ -0,0 +1,530 @@
|
|||
//XAudioJS realtime audio output compatibility library
|
||||
//Copyright (C) 2010-2015 Grant Galitz
|
||||
//Released to Public Domain
|
||||
var XAudioJSscriptsHandle = document.getElementsByTagName("script");
|
||||
var XAudioJSsourceHandle = XAudioJSscriptsHandle[XAudioJSscriptsHandle.length-1].src;
|
||||
function XAudioServer(channels, sampleRate, minBufferSize, maxBufferSize, underRunCallback, heartbeatCallback, postheartbeatCallback, volume, failureCallback, userEventLatch) {
|
||||
XAudioJSChannelsAllocated = Math.max(channels, 1);
|
||||
this.XAudioJSSampleRate = Math.abs(sampleRate);
|
||||
XAudioJSMinBufferSize = (minBufferSize >= (XAudioJSSamplesPerCallback * XAudioJSChannelsAllocated) && minBufferSize < maxBufferSize) ? (minBufferSize & (-XAudioJSChannelsAllocated)) : (XAudioJSSamplesPerCallback * XAudioJSChannelsAllocated);
|
||||
XAudioJSMaxBufferSize = (Math.floor(maxBufferSize) > XAudioJSMinBufferSize + XAudioJSChannelsAllocated) ? (maxBufferSize & (-XAudioJSChannelsAllocated)) : (XAudioJSMinBufferSize * XAudioJSChannelsAllocated);
|
||||
this.underRunCallback = (typeof underRunCallback == "function") ? underRunCallback : function () {};
|
||||
XAudioJSCallbackAPIEventNotificationCallback = (typeof heartbeatCallback == "function") ? heartbeatCallback : null;
|
||||
XAudioJSCallbackAPIEventNotificationCallback2 = (typeof postheartbeatCallback == "function") ? postheartbeatCallback : null;
|
||||
XAudioJSVolume = (volume >= 0 && volume <= 1) ? volume : 1;
|
||||
this.failureCallback = (typeof failureCallback == "function") ? failureCallback : function () { throw(new Error("XAudioJS has encountered a fatal error.")); };
|
||||
this.userEventLatch = (typeof userEventLatch == "object") ? userEventLatch : null;
|
||||
this.initializeAudio();
|
||||
}
|
||||
XAudioServer.prototype.MOZWriteAudioNoCallback = function (buffer, upTo) {
|
||||
//Resample before passing to the moz audio api:
|
||||
var bufferLength = Math.min(buffer.length, upTo);
|
||||
for (var bufferIndex = 0; bufferIndex < bufferLength;) {
|
||||
var sliceLength = Math.min(bufferLength - bufferIndex, XAudioJSMaxBufferSize);
|
||||
for (var sliceIndex = 0; sliceIndex < sliceLength; ++sliceIndex) {
|
||||
XAudioJSAudioContextSampleBuffer[sliceIndex] = buffer[bufferIndex++];
|
||||
}
|
||||
var resampleLength = XAudioJSResampleControl.resampler(sliceIndex);
|
||||
if (resampleLength > 0) {
|
||||
var resampledResult = XAudioJSResampleControl.outputBuffer;
|
||||
var resampledBuffer = XAudioJSGetArraySlice(resampledResult, resampleLength);
|
||||
this.samplesAlreadyWritten += this.audioHandleMoz.mozWriteAudio(resampledBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
XAudioServer.prototype.callbackBasedWriteAudioNoCallback = function (buffer, upTo) {
|
||||
//Callback-centered audio APIs:
|
||||
var bufferLength = Math.min(buffer.length, upTo);
|
||||
for (var bufferCounter = 0; bufferCounter < bufferLength && XAudioJSAudioBufferSize < XAudioJSMaxBufferSize;) {
|
||||
XAudioJSAudioContextSampleBuffer[XAudioJSAudioBufferSize++] = buffer[bufferCounter++];
|
||||
}
|
||||
}
|
||||
/*Pass your samples into here!
|
||||
Pack your samples as a one-dimenional array
|
||||
With the channel samples packed uniformly.
|
||||
examples:
|
||||
mono - [left, left, left, left]
|
||||
stereo - [left, right, left, right, left, right, left, right]
|
||||
*/
|
||||
XAudioServer.prototype.writeAudio = function (buffer, upTo) {
|
||||
switch (this.audioType) {
|
||||
case 0:
|
||||
this.MOZWriteAudioNoCallback(buffer, upTo);
|
||||
this.MOZExecuteCallback();
|
||||
break;
|
||||
case 2:
|
||||
this.checkFlashInit();
|
||||
case 1:
|
||||
this.callbackBasedWriteAudioNoCallback(buffer, upTo);
|
||||
this.callbackBasedExecuteCallback();
|
||||
break;
|
||||
default:
|
||||
this.failureCallback();
|
||||
}
|
||||
}
|
||||
/*Pass your samples into here if you don't want automatic callback calling:
|
||||
Pack your samples as a one-dimenional array
|
||||
With the channel samples packed uniformly.
|
||||
examples:
|
||||
mono - [left, left, left, left]
|
||||
stereo - [left, right, left, right, left, right, left, right]
|
||||
Useful in preventing infinite recursion issues with calling writeAudio inside your callback.
|
||||
*/
|
||||
XAudioServer.prototype.writeAudioNoCallback = function (buffer, upTo) {
|
||||
switch (this.audioType) {
|
||||
case 0:
|
||||
this.MOZWriteAudioNoCallback(buffer, upTo);
|
||||
break;
|
||||
case 2:
|
||||
this.checkFlashInit();
|
||||
case 1:
|
||||
this.callbackBasedWriteAudioNoCallback(buffer, upTo);
|
||||
break;
|
||||
default:
|
||||
this.failureCallback();
|
||||
}
|
||||
}
|
||||
//Developer can use this to see how many samples to write (example: minimum buffer allotment minus remaining samples left returned from this function to make sure maximum buffering is done...)
|
||||
//If null is returned, then that means metric could not be done.
|
||||
XAudioServer.prototype.remainingBuffer = function () {
|
||||
switch (this.audioType) {
|
||||
case 0:
|
||||
return Math.floor((this.samplesAlreadyWritten - this.audioHandleMoz.mozCurrentSampleOffset()) * XAudioJSResampleControl.ratioWeight / XAudioJSChannelsAllocated) * XAudioJSChannelsAllocated;
|
||||
case 2:
|
||||
this.checkFlashInit();
|
||||
case 1:
|
||||
return (Math.floor((XAudioJSResampledSamplesLeft() * XAudioJSResampleControl.ratioWeight) / XAudioJSChannelsAllocated) * XAudioJSChannelsAllocated) + XAudioJSAudioBufferSize;
|
||||
default:
|
||||
this.failureCallback();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
XAudioServer.prototype.MOZExecuteCallback = function () {
|
||||
//mozAudio:
|
||||
var samplesRequested = XAudioJSMinBufferSize - this.remainingBuffer();
|
||||
if (samplesRequested > 0) {
|
||||
var buffer = this.underRunCallback(samplesRequested);
|
||||
this.MOZWriteAudioNoCallback(buffer, buffer.length);
|
||||
}
|
||||
}
|
||||
XAudioServer.prototype.callbackBasedExecuteCallback = function () {
|
||||
//WebKit /Flash Audio:
|
||||
var samplesRequested = XAudioJSMinBufferSize - this.remainingBuffer();
|
||||
if (samplesRequested > 0) {
|
||||
var buffer = this.underRunCallback(samplesRequested);
|
||||
this.callbackBasedWriteAudioNoCallback(buffer, buffer.length);
|
||||
}
|
||||
}
|
||||
//If you just want your callback called for any possible refill (Execution of callback is still conditional):
|
||||
XAudioServer.prototype.executeCallback = function () {
|
||||
switch (this.audioType) {
|
||||
case 0:
|
||||
this.MOZExecuteCallback();
|
||||
break;
|
||||
case 2:
|
||||
this.checkFlashInit();
|
||||
case 1:
|
||||
this.callbackBasedExecuteCallback();
|
||||
break;
|
||||
default:
|
||||
this.failureCallback();
|
||||
}
|
||||
}
|
||||
//DO NOT CALL THIS, the lib calls this internally!
|
||||
XAudioServer.prototype.initializeAudio = function () {
|
||||
try {
|
||||
this.initializeMozAudio();
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
this.initializeWebAudio();
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
this.initializeFlashAudio();
|
||||
}
|
||||
catch (error) {
|
||||
this.audioType = -1;
|
||||
this.failureCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
XAudioServer.prototype.initializeMozAudio = function () {
|
||||
this.audioHandleMoz = new Audio();
|
||||
this.audioHandleMoz.mozSetup(XAudioJSChannelsAllocated, XAudioJSMozAudioSampleRate);
|
||||
this.audioHandleMoz.volume = XAudioJSVolume;
|
||||
this.samplesAlreadyWritten = 0;
|
||||
this.audioType = 0;
|
||||
//if (navigator.platform != "MacIntel" && navigator.platform != "MacPPC") {
|
||||
//Add some additional buffering space to workaround a moz audio api issue:
|
||||
var bufferAmount = (this.XAudioJSSampleRate * XAudioJSChannelsAllocated / 10) | 0;
|
||||
bufferAmount -= bufferAmount % XAudioJSChannelsAllocated;
|
||||
this.samplesAlreadyWritten -= bufferAmount;
|
||||
//}
|
||||
this.initializeResampler(XAudioJSMozAudioSampleRate);
|
||||
}
|
||||
XAudioServer.prototype.initializeWebAudio = function () {
|
||||
if (typeof AudioContext == "undefined" || typeof XAudioJSWebAudioContextHandle == "undefined") {
|
||||
throw null;
|
||||
}
|
||||
else {
|
||||
if (!this.userEventLatch) {
|
||||
this.setupWebAudio();
|
||||
}
|
||||
else {
|
||||
var parentObj = this;
|
||||
var XAudioJSWebAudioDelayedEvent = 0;
|
||||
this.userEventLatch.addEventListener("click", function () {
|
||||
if (XAudioJSWebAudioDelayedEvent == 0) {
|
||||
parentObj.setupWebAudio();
|
||||
XAudioJSWebAudioDelayedEvent |= 1;
|
||||
}
|
||||
}, false);
|
||||
this.userEventLatch.addEventListener("touchstart", function () {
|
||||
if (XAudioJSWebAudioDelayedEvent < 2) {
|
||||
parentObj.setupWebAudio();
|
||||
XAudioJSWebAudioDelayedEvent |= 2;
|
||||
}
|
||||
}, false);
|
||||
this.userEventLatch.addEventListener("touchend", function () {
|
||||
if (XAudioJSWebAudioDelayedEvent < 4) {
|
||||
parentObj.setupWebAudio();
|
||||
XAudioJSWebAudioDelayedEvent |= 4;
|
||||
}
|
||||
}, false);
|
||||
//TODO: Restructure API to not have to potentially lie to end client about
|
||||
//the samples in buffer before user driven event callback that actually starts WA.
|
||||
this.resetCallbackAPIAudioBuffer(44100);
|
||||
}
|
||||
this.audioType = 1;
|
||||
}
|
||||
}
|
||||
XAudioServer.prototype.setupWebAudio = function () {
|
||||
if (XAudioJSWebAudioLaunchedContext) {
|
||||
XAudioJSWebAudioContextHandle.close();
|
||||
}
|
||||
try {
|
||||
XAudioJSWebAudioContextHandle = new AudioContext(); //Create a system audio context.
|
||||
}
|
||||
catch (error) {
|
||||
XAudioJSWebAudioContextHandle = new webkitAudioContext(); //Create a system audio context.
|
||||
}
|
||||
XAudioJSWebAudioLaunchedContext = true;
|
||||
if (XAudioJSWebAudioAudioNode) {
|
||||
XAudioJSWebAudioAudioNode.disconnect();
|
||||
XAudioJSWebAudioAudioNode.onaudioprocess = null;
|
||||
XAudioJSWebAudioAudioNode = null;
|
||||
}
|
||||
try {
|
||||
XAudioJSWebAudioAudioNode = XAudioJSWebAudioContextHandle.createScriptProcessor(XAudioJSSamplesPerCallback, 0, XAudioJSChannelsAllocated); //Create the js event node.
|
||||
}
|
||||
catch (error) {
|
||||
XAudioJSWebAudioAudioNode = XAudioJSWebAudioContextHandle.createJavaScriptNode(XAudioJSSamplesPerCallback, 0, XAudioJSChannelsAllocated); //Create the js event node.
|
||||
}
|
||||
XAudioJSWebAudioAudioNode.onaudioprocess = XAudioJSWebAudioEvent; //Connect the audio processing event to a handling function so we can manipulate output
|
||||
XAudioJSWebAudioAudioNode.connect(XAudioJSWebAudioContextHandle.destination); //Send and chain the output of the audio manipulation to the system audio output.
|
||||
this.resetCallbackAPIAudioBuffer(XAudioJSWebAudioContextHandle.sampleRate);
|
||||
/*
|
||||
Firefox has a bug in its web audio implementation...
|
||||
The node may randomly stop playing on Mac OS X for no
|
||||
good reason. Keep a watchdog timer to restart the failed
|
||||
node if it glitches. Google Chrome never had this issue.
|
||||
*/
|
||||
XAudioJSWebAudioWatchDogLast = (new Date()).getTime();
|
||||
if (!XAudioJSWebAudioWatchDogTimer && navigator.userAgent.indexOf('Gecko/') > -1) {
|
||||
if (XAudioJSWebAudioWatchDogTimer) {
|
||||
clearInterval(XAudioJSWebAudioWatchDogTimer);
|
||||
}
|
||||
var parentObj = this;
|
||||
XAudioJSWebAudioWatchDogTimer = setInterval(function () {
|
||||
if(typeof XAudioJSWebAudioContextHandle.state != "undefined") {
|
||||
if (XAudioJSWebAudioContextHandle.state === 'suspended') {
|
||||
XAudioJSWebAudioWatchDogLast = (new Date()).getTime();
|
||||
try {
|
||||
XAudioJSWebAudioContextHandle.resume();
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
else {
|
||||
var timeDiff = (new Date()).getTime() - XAudioJSWebAudioWatchDogLast;
|
||||
if (timeDiff > 500) {
|
||||
parentObj.setupWebAudio();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
XAudioServer.prototype.initializeFlashAudio = function () {
|
||||
var existingFlashload = document.getElementById("XAudioJS");
|
||||
this.flashInitialized = false;
|
||||
this.resetCallbackAPIAudioBuffer(44100);
|
||||
switch (XAudioJSChannelsAllocated) {
|
||||
case 1:
|
||||
XAudioJSFlashTransportEncoder = XAudioJSGenerateFlashMonoString;
|
||||
break;
|
||||
case 2:
|
||||
XAudioJSFlashTransportEncoder = XAudioJSGenerateFlashStereoString;
|
||||
break;
|
||||
default:
|
||||
XAudioJSFlashTransportEncoder = XAudioJSGenerateFlashSurroundString;
|
||||
}
|
||||
if (existingFlashload == null) {
|
||||
this.audioHandleFlash = null;
|
||||
var thisObj = this;
|
||||
var mainContainerNode = document.createElement("div");
|
||||
mainContainerNode.setAttribute("style", "position: fixed; bottom: 0px; right: 0px; margin: 0px; padding: 0px; border: none; width: 8px; height: 8px; overflow: hidden; z-index: -1000; ");
|
||||
var containerNode = document.createElement("div");
|
||||
containerNode.setAttribute("style", "position: static; border: none; width: 0px; height: 0px; visibility: hidden; margin: 8px; padding: 0px;");
|
||||
containerNode.setAttribute("id", "XAudioJS");
|
||||
mainContainerNode.appendChild(containerNode);
|
||||
document.getElementsByTagName("body")[0].appendChild(mainContainerNode);
|
||||
swfobject.embedSWF(
|
||||
XAudioJSsourceHandle.substring(0, XAudioJSsourceHandle.length - 9) + "JS.swf",
|
||||
"XAudioJS",
|
||||
"8",
|
||||
"8",
|
||||
"9.0.0",
|
||||
"",
|
||||
{},
|
||||
{"allowscriptaccess":"always"},
|
||||
{"style":"position: static; visibility: hidden; margin: 8px; padding: 0px; border: none"},
|
||||
function (event) {
|
||||
if (event.success) {
|
||||
thisObj.audioHandleFlash = event.ref;
|
||||
thisObj.checkFlashInit();
|
||||
}
|
||||
else {
|
||||
thisObj.failureCallback();
|
||||
thisObj.audioType = -1;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.audioHandleFlash = existingFlashload;
|
||||
this.checkFlashInit();
|
||||
}
|
||||
this.audioType = 2;
|
||||
}
|
||||
XAudioServer.prototype.changeVolume = function (newVolume) {
|
||||
if (newVolume >= 0 && newVolume <= 1) {
|
||||
XAudioJSVolume = newVolume;
|
||||
switch (this.audioType) {
|
||||
case 0:
|
||||
this.audioHandleMoz.volume = XAudioJSVolume;
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
if (this.flashInitialized) {
|
||||
this.audioHandleFlash.changeVolume(XAudioJSVolume);
|
||||
}
|
||||
else {
|
||||
this.checkFlashInit();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.failureCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
//Checks to see if the NPAPI Adobe Flash bridge is ready yet:
|
||||
XAudioServer.prototype.checkFlashInit = function () {
|
||||
if (!this.flashInitialized) {
|
||||
try {
|
||||
if (this.audioHandleFlash && this.audioHandleFlash.initialize) {
|
||||
this.flashInitialized = true;
|
||||
this.audioHandleFlash.initialize(XAudioJSChannelsAllocated, XAudioJSVolume);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
this.flashInitialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Set up the resampling:
|
||||
XAudioServer.prototype.resetCallbackAPIAudioBuffer = function (APISampleRate) {
|
||||
XAudioJSAudioBufferSize = XAudioJSResampleBufferEnd = XAudioJSResampleBufferStart = 0;
|
||||
this.initializeResampler(APISampleRate);
|
||||
XAudioJSResampledBuffer = this.getFloat32(XAudioJSResampleBufferSize);
|
||||
}
|
||||
XAudioServer.prototype.initializeResampler = function (sampleRate) {
|
||||
XAudioJSAudioContextSampleBuffer = this.getFloat32(XAudioJSMaxBufferSize);
|
||||
XAudioJSResampleControl = new Resampler(this.XAudioJSSampleRate, sampleRate, XAudioJSChannelsAllocated, XAudioJSAudioContextSampleBuffer);
|
||||
XAudioJSResampleBufferSize = XAudioJSResampleControl.outputBuffer.length;
|
||||
}
|
||||
XAudioServer.prototype.getFloat32 = function (size) {
|
||||
try {
|
||||
return new Float32Array(size);
|
||||
}
|
||||
catch (error) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
function XAudioJSFlashAudioEvent() { //The callback that flash calls...
|
||||
XAudioJSCallbackAPIEventNotificationCallbackCompatTimerClear();
|
||||
XAudioJSCallbackAPIEventNotification();
|
||||
XAudioJSResampleRefill();
|
||||
var outputStr = XAudioJSFlashTransportEncoder();
|
||||
XAudioJSCallbackAPIEventNotification2();
|
||||
return outputStr;
|
||||
}
|
||||
function XAudioJSGenerateFlashSurroundString() { //Convert the arrays to one long string for speed.
|
||||
var XAudioJSTotalSamples = XAudioJSSamplesPerCallback << 1;
|
||||
if (XAudioJSBinaryString.length > XAudioJSTotalSamples) {
|
||||
XAudioJSBinaryString = [];
|
||||
}
|
||||
XAudioJSTotalSamples = 0;
|
||||
for (var index = 0; index < XAudioJSSamplesPerCallback && XAudioJSResampleBufferStart != XAudioJSResampleBufferEnd; ++index) {
|
||||
//Sanitize the buffer:
|
||||
XAudioJSBinaryString[XAudioJSTotalSamples++] = String.fromCharCode(((Math.min(Math.max(XAudioJSResampledBuffer[XAudioJSResampleBufferStart++] + 1, 0), 2) * 0x3FFF) | 0) + 0x3000);
|
||||
XAudioJSBinaryString[XAudioJSTotalSamples++] = String.fromCharCode(((Math.min(Math.max(XAudioJSResampledBuffer[XAudioJSResampleBufferStart++] + 1, 0), 2) * 0x3FFF) | 0) + 0x3000);
|
||||
XAudioJSResampleBufferStart += XAudioJSChannelsAllocated - 2;
|
||||
if (XAudioJSResampleBufferStart == XAudioJSResampleBufferSize) {
|
||||
XAudioJSResampleBufferStart = 0;
|
||||
}
|
||||
}
|
||||
return XAudioJSBinaryString.join("");
|
||||
}
|
||||
function XAudioJSGenerateFlashStereoString() { //Convert the arrays to one long string for speed.
|
||||
var XAudioJSTotalSamples = XAudioJSSamplesPerCallback << 1;
|
||||
if (XAudioJSBinaryString.length > XAudioJSTotalSamples) {
|
||||
XAudioJSBinaryString = [];
|
||||
}
|
||||
for (var index = 0; index < XAudioJSTotalSamples && XAudioJSResampleBufferStart != XAudioJSResampleBufferEnd;) {
|
||||
//Sanitize the buffer:
|
||||
XAudioJSBinaryString[index++] = String.fromCharCode(((Math.min(Math.max(XAudioJSResampledBuffer[XAudioJSResampleBufferStart++] + 1, 0), 2) * 0x3FFF) | 0) + 0x3000);
|
||||
XAudioJSBinaryString[index++] = String.fromCharCode(((Math.min(Math.max(XAudioJSResampledBuffer[XAudioJSResampleBufferStart++] + 1, 0), 2) * 0x3FFF) | 0) + 0x3000);
|
||||
if (XAudioJSResampleBufferStart == XAudioJSResampleBufferSize) {
|
||||
XAudioJSResampleBufferStart = 0;
|
||||
}
|
||||
}
|
||||
return XAudioJSBinaryString.join("");
|
||||
}
|
||||
function XAudioJSGenerateFlashMonoString() { //Convert the array to one long string for speed.
|
||||
if (XAudioJSBinaryString.length > XAudioJSSamplesPerCallback) {
|
||||
XAudioJSBinaryString = [];
|
||||
}
|
||||
for (var index = 0; index < XAudioJSSamplesPerCallback && XAudioJSResampleBufferStart != XAudioJSResampleBufferEnd;) {
|
||||
//Sanitize the buffer:
|
||||
XAudioJSBinaryString[index++] = String.fromCharCode(((Math.min(Math.max(XAudioJSResampledBuffer[XAudioJSResampleBufferStart++] + 1, 0), 2) * 0x3FFF) | 0) + 0x3000);
|
||||
if (XAudioJSResampleBufferStart == XAudioJSResampleBufferSize) {
|
||||
XAudioJSResampleBufferStart = 0;
|
||||
}
|
||||
}
|
||||
return XAudioJSBinaryString.join("");
|
||||
}
|
||||
//Some Required Globals:
|
||||
var XAudioJSWebAudioContextHandle = null;
|
||||
var XAudioJSWebAudioAudioNode = null;
|
||||
var XAudioJSWebAudioWatchDogTimer = null;
|
||||
var XAudioJSCallbackAPIEventNotificationCallback = null;
|
||||
var XAudioJSCallbackAPIEventNotificationCallback2 = null;
|
||||
var XAudioJSCallbackAPIEventNotificationCallbackCompatTimer = setInterval(XAudioJSCallbackAPIEventNotificationDual, 16);
|
||||
var XAudioJSWebAudioWatchDogLast = false;
|
||||
var XAudioJSWebAudioLaunchedContext = false;
|
||||
var XAudioJSAudioContextSampleBuffer = [];
|
||||
var XAudioJSResampledBuffer = [];
|
||||
var XAudioJSMinBufferSize = 15000;
|
||||
var XAudioJSMaxBufferSize = 25000;
|
||||
var XAudioJSChannelsAllocated = 1;
|
||||
var XAudioJSVolume = 1;
|
||||
var XAudioJSResampleControl = null;
|
||||
var XAudioJSAudioBufferSize = 0;
|
||||
var XAudioJSResampleBufferStart = 0;
|
||||
var XAudioJSResampleBufferEnd = 0;
|
||||
var XAudioJSResampleBufferSize = 0;
|
||||
var XAudioJSMozAudioSampleRate = 44100;
|
||||
var XAudioJSSamplesPerCallback = 2048; //Has to be between 2048 and 4096 (If over, then samples are ignored, if under then silence is added).
|
||||
var XAudioJSFlashTransportEncoder = null;
|
||||
var XAudioJSBinaryString = [];
|
||||
function XAudioJSWebAudioEvent(event) { //Web Audio API callback...
|
||||
if (XAudioJSWebAudioWatchDogTimer) {
|
||||
XAudioJSWebAudioWatchDogLast = (new Date()).getTime();
|
||||
}
|
||||
//Find all output channels:
|
||||
for (var bufferCount = 0, buffers = []; bufferCount < XAudioJSChannelsAllocated; ++bufferCount) {
|
||||
buffers[bufferCount] = event.outputBuffer.getChannelData(bufferCount);
|
||||
}
|
||||
XAudioJSCallbackAPIEventNotificationCallbackCompatTimerClear();
|
||||
XAudioJSCallbackAPIEventNotification();
|
||||
//Make sure we have resampled samples ready:
|
||||
XAudioJSResampleRefill();
|
||||
//Copy samples from XAudioJS to the Web Audio API:
|
||||
for (var index = 0; index < XAudioJSSamplesPerCallback && XAudioJSResampleBufferStart != XAudioJSResampleBufferEnd; ++index) {
|
||||
for (bufferCount = 0; bufferCount < XAudioJSChannelsAllocated; ++bufferCount) {
|
||||
buffers[bufferCount][index] = XAudioJSResampledBuffer[XAudioJSResampleBufferStart++] * XAudioJSVolume;
|
||||
}
|
||||
if (XAudioJSResampleBufferStart == XAudioJSResampleBufferSize) {
|
||||
XAudioJSResampleBufferStart = 0;
|
||||
}
|
||||
}
|
||||
//Pad with silence if we're underrunning:
|
||||
while (index < XAudioJSSamplesPerCallback) {
|
||||
for (bufferCount = 0; bufferCount < XAudioJSChannelsAllocated; ++bufferCount) {
|
||||
buffers[bufferCount][index] = 0;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
XAudioJSCallbackAPIEventNotification2();
|
||||
}
|
||||
function XAudioJSResampleRefill() {
|
||||
if (XAudioJSAudioBufferSize > 0) {
|
||||
//Resample a chunk of audio:
|
||||
var resampleLength = XAudioJSResampleControl.resampler(XAudioJSAudioBufferSize);
|
||||
var resampledResult = XAudioJSResampleControl.outputBuffer;
|
||||
for (var index2 = 0; index2 < resampleLength;) {
|
||||
XAudioJSResampledBuffer[XAudioJSResampleBufferEnd++] = resampledResult[index2++];
|
||||
if (XAudioJSResampleBufferEnd == XAudioJSResampleBufferSize) {
|
||||
XAudioJSResampleBufferEnd = 0;
|
||||
}
|
||||
if (XAudioJSResampleBufferStart == XAudioJSResampleBufferEnd) {
|
||||
XAudioJSResampleBufferStart += XAudioJSChannelsAllocated;
|
||||
if (XAudioJSResampleBufferStart == XAudioJSResampleBufferSize) {
|
||||
XAudioJSResampleBufferStart = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
XAudioJSAudioBufferSize = 0;
|
||||
}
|
||||
}
|
||||
function XAudioJSCallbackAPIEventNotificationCallbackCompatTimerClear() {
|
||||
if (XAudioJSCallbackAPIEventNotificationCallbackCompatTimer) {
|
||||
clearInterval(XAudioJSCallbackAPIEventNotificationCallbackCompatTimer);
|
||||
}
|
||||
}
|
||||
function XAudioJSCallbackAPIEventNotification() {
|
||||
if (typeof XAudioJSCallbackAPIEventNotificationCallback == "function") {
|
||||
XAudioJSCallbackAPIEventNotificationCallback();
|
||||
}
|
||||
}
|
||||
function XAudioJSCallbackAPIEventNotification2() {
|
||||
if (typeof XAudioJSCallbackAPIEventNotificationCallback2 == "function") {
|
||||
XAudioJSCallbackAPIEventNotificationCallback2();
|
||||
}
|
||||
}
|
||||
function XAudioJSCallbackAPIEventNotificationDual() {
|
||||
XAudioJSCallbackAPIEventNotification();
|
||||
XAudioJSCallbackAPIEventNotification2();
|
||||
}
|
||||
function XAudioJSResampledSamplesLeft() {
|
||||
return ((XAudioJSResampleBufferStart <= XAudioJSResampleBufferEnd) ? 0 : XAudioJSResampleBufferSize) + XAudioJSResampleBufferEnd - XAudioJSResampleBufferStart;
|
||||
}
|
||||
function XAudioJSGetArraySlice(buffer, lengthOf) {
|
||||
//Typed array and normal array buffer section referencing:
|
||||
try {
|
||||
return buffer.subarray(0, lengthOf);
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
//Regular array pass:
|
||||
buffer.length = lengthOf;
|
||||
return buffer;
|
||||
}
|
||||
catch (error) {
|
||||
//Nightly Firefox 4 used to have the subarray function named as slice:
|
||||
return buffer.slice(0, lengthOf);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue