mirror of
https://github.com/schibo/1964js.git
synced 2025-04-02 10:52:54 -04:00
2014 lines
76 KiB
CoffeeScript
2014 lines
76 KiB
CoffeeScript
###1964js - JavaScript/HTML5 port of 1964 - N64 emulator
|
|
Copyright (C) 2012 Joel Middendorf
|
|
|
|
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 2
|
|
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, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.###
|
|
#jslint todo: true, bitwise: true
|
|
|
|
#globals window, mat4, C1964jsRenderer, consts, dec2hex, Float32Array
|
|
"use strict"
|
|
|
|
class C1964jsVideoHLE
|
|
constructor: (core, glx) ->
|
|
@ucode = -1
|
|
@processDisplayList = @callBind @processDisplayList, this
|
|
|
|
i = undefined
|
|
###*
|
|
* @const
|
|
###
|
|
@core = core #only needed for gfxHelpers prototypes to access.
|
|
###*
|
|
* @const
|
|
###
|
|
@gl = glx
|
|
|
|
@fogIsImplemented = false #enable this when we supoort fog
|
|
|
|
#todo: make gRSP a class object.
|
|
@RICE_MATRIX_STACK = 60
|
|
@MAX_TEXTURES = 8
|
|
@MAX_VERTICES = 80
|
|
@MAX_TILES = 8
|
|
@tmem = new Uint8Array(1024 * 4)
|
|
@tlut = new Uint8Array(1024 * 4)
|
|
@activeTile = 0
|
|
@textureTile = []
|
|
@zDepthImage = {fmt: 0, siz: 0, width: 0, addr: 0}
|
|
@zColorImage = {fmt: 0, siz: 0, width: 0, addr: 0}
|
|
###*
|
|
* @const
|
|
###
|
|
@N64VertexList = []
|
|
@geometryMode = 0
|
|
###*
|
|
* @const
|
|
###
|
|
@gRSP = {}
|
|
###*
|
|
* @const
|
|
###
|
|
@gRSPlights = [{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]
|
|
###*
|
|
* @const
|
|
###
|
|
@gRSPn64lights = [{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]
|
|
@gRSPnumLights = 0
|
|
@matToLoad = mat4.create()
|
|
@lightingMat = mat4.create()
|
|
@triangleVertexPositionBuffer = `undefined`
|
|
@triangleVertexColorBuffer = `undefined`
|
|
@dlistStackPointer = 0
|
|
@dlistStack = []
|
|
|
|
if core.isLittleEndian is 1 and core.useByteCompatibilityMode is false
|
|
@renderer = new C1964jsRendererLE @core.settings, @core.webGL.gl, @core.webGL
|
|
else
|
|
@renderer = new C1964jsRenderer @core.settings, @core.webGL.gl, @core.webGL
|
|
|
|
@texImg = {}
|
|
@segments = []
|
|
@gl.useProgram @core.webGL.shaderProgram
|
|
###*
|
|
* @const
|
|
###
|
|
@primColor = [0.0, 0.0, 0.0, 0.0]
|
|
###*
|
|
* @const
|
|
###
|
|
@fillColor = [0.0, 0.0, 0.0, 0.0]
|
|
###*
|
|
* @const
|
|
###
|
|
@blendColor = [0.0, 0.0, 0.0, 0.0]
|
|
###*
|
|
* @const
|
|
###
|
|
@envColor = [0.0, 0.0, 0.0, 0.0]
|
|
###*
|
|
* @const
|
|
###
|
|
@triVertices = new Float32Array(16384)
|
|
###*
|
|
* @const
|
|
###
|
|
@triColorVertices = new Uint8Array(16384)
|
|
###*
|
|
* @const
|
|
###
|
|
@triTextureCoords = new Float32Array(16384)
|
|
|
|
@tempVec4 = new Float32Array 4
|
|
@tempVec3Buffer = new ArrayBuffer(3 * @MAX_VERTICES * 4)
|
|
|
|
@otherModeL = 0
|
|
@otherModeH = 0
|
|
@cycleType = 0
|
|
@alphaTestEnabled = 0
|
|
@bShade = false
|
|
@bTextureGen = false
|
|
@bLightingEnable = false
|
|
@bFogEnable = false
|
|
@bZBufferEnable = false
|
|
@colorsTexture0 = @gl.createTexture()
|
|
@colorsTexture1 = @gl.createTexture()
|
|
@renderStateChanged = false
|
|
@inverseTransposeCalculated = false
|
|
|
|
###*
|
|
* @const
|
|
###
|
|
@normalMat = new Float32Array 4
|
|
###*
|
|
* @const
|
|
###
|
|
@modelViewInverse = mat4.create()
|
|
###*
|
|
* @const
|
|
###
|
|
@modelViewTransposedInverse = mat4.create()
|
|
|
|
# Native Viewport
|
|
@n64ViewportWidth = 640
|
|
@n64ViewportHeight = 480
|
|
@n64ViewportLeft = 0
|
|
@n64ViewportTop = 0
|
|
@n64ViewportRight = 320
|
|
@n64ViewportBottom = 240
|
|
|
|
###*
|
|
* Microcode 0 LUT
|
|
* @type {!Array<!function(number)>}
|
|
* @const
|
|
###
|
|
|
|
i = 0
|
|
while i < @MAX_TILES
|
|
@textureTile[i] = []
|
|
i += 1
|
|
i = 0
|
|
while i < @MAX_VERTICES
|
|
@N64VertexList[i] = {}
|
|
i += 1
|
|
i = 0
|
|
while i < consts.MAX_DL_STACK_SIZE
|
|
@dlistStack[i] = {}
|
|
i += 1
|
|
i = 0
|
|
while i < @segments.length
|
|
@segments[i] = 0
|
|
i += 1
|
|
@gRSP.projectionMtxs = []
|
|
@gRSP.modelviewMtxs = []
|
|
@gRSP.ambientLightIndex = 0
|
|
@gRSP.ambientLightColor = 0
|
|
@gRSP.fAmbientLightA = 0
|
|
@gRSP.fAmbientLightR = 0
|
|
@gRSP.fAmbientLightG = 0
|
|
@gRSP.fAmbientLightB = 0
|
|
|
|
@gl.clearColor 0.0, 0.0, 0.0, 0.0
|
|
@gl.depthFunc @gl.LEQUAL
|
|
@gl.clearDepth 1.0
|
|
@gl.disable @gl.DEPTH_TEST
|
|
|
|
#todo: allocate on-demand
|
|
i = 0
|
|
while i < @RICE_MATRIX_STACK
|
|
@gRSP.projectionMtxs[i] = mat4.create()
|
|
@gRSP.modelviewMtxs[i] = mat4.create()
|
|
i += 1
|
|
@triangleVertexTextureCoordBuffer = `undefined`
|
|
@resetMatrices()
|
|
@combine = new Uint32Array(16)
|
|
@makeUcodeData()
|
|
@makeUcodeMap()
|
|
@crcTable = @makeCRCTable()
|
|
|
|
@vertexMult = 0
|
|
|
|
@vertexMultVals = [
|
|
10, # ucode 0 - Mario
|
|
2, # ucode 1 - GBI1
|
|
10, # ucode 2 - Golden Eye
|
|
2, # ucode 3 - S2DEX GBI2
|
|
5, # ucode 4 - Wave Racer
|
|
2, # ucode 5 - BGI2
|
|
10, # ucode 6 - DKR
|
|
2, # ucode 7 - S2DEX
|
|
10, # ucode 8 - ucode 0 with sprite2D, for Demo Puzzle Master 64
|
|
10, # ucode 9 - Perfect Dark
|
|
2, # ucode 10 - Conker
|
|
10, # ucode 11 - Gemini
|
|
2, # ucode 12 - Silicon Valley, Spacestation
|
|
2, # ucode 13 - modified ucode S2DEX
|
|
2, # ucode 14 - OgreBattle Background
|
|
10, # ucode 15 - ucode 0 with sprite2D
|
|
5, # ucode 16 - Star War, Shadow of Empire
|
|
2, # ucode 17 - Star Wars - Rogue Squadron,
|
|
2, # ucode 18 - World Driver Championship, check me here
|
|
2, # ucode 19 - Last Legion UX, check me here
|
|
2 # ucode 20 - ZSortp
|
|
]
|
|
return
|
|
|
|
makeUcodeMap: () ->
|
|
@microcodeMap0 = [@RSP_GBI1_SpNoop, @RSP_GBI0_Mtx, @RSP_GBI1_Reserved, @RSP_GBI1_MoveMem,
|
|
@RSP_GBI0_Vtx, @RSP_GBI1_Reserved, @RSP_GBI0_DL, @RSP_GBI1_Reserved,
|
|
@RSP_GBI1_Reserved, @RSP_GBI0_Sprite2DBase, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_GBI0_Tri4, @RSP_GBI1_RDPHalf_Cont, @RSP_GBI1_RDPHalf_2,
|
|
@RSP_GBI1_RDPHalf_1, @RSP_GBI1_Line3D, @RSP_GBI1_ClearGeometryMode, @RSP_GBI1_SetGeometryMode,
|
|
@RSP_GBI1_EndDL, @RSP_GBI1_SetOtherModeL, @RSP_GBI1_SetOtherModeH, @RSP_GBI1_Texture,
|
|
@RSP_GBI1_MoveWord, @RSP_GBI1_PopMtx, @RSP_GBI1_CullDL, @RSP_GBI1_Tri1,
|
|
@RSP_GBI1_Noop, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RDP_TriFill, @RDP_TriFillZ, @RDP_TriTxtr, @RDP_TriTxtrZ,
|
|
@RDP_TriShade, @RDP_TriShadeZ, @RDP_TriShadeTxtr, @RDP_TriShadeTxtrZ,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing, @RSP_RDP_Nothing,
|
|
@DLParser_TexRect, @DLParser_TexRectFlip, @DLParser_RDPLoadSynch, @DLParser_RDPPipeSynch,
|
|
@DLParser_RDPTileSynch, @DLParser_RDPFullSynch, @DLParser_SetKeyGB, @DLParser_SetKeyR,
|
|
@DLParser_SetConvert, @DLParser_SetScissor, @DLParser_SetPrimDepth, @DLParser_RDPSetOtherMode,
|
|
@DLParser_LoadTLut, @RSP_RDP_Nothing, @DLParser_SetTileSize, @DLParser_LoadBlock,
|
|
@DLParser_LoadTile, @DLParser_SetTile, @DLParser_FillRect, @DLParser_SetFillColor,
|
|
@DLParser_SetFogColor, @DLParser_SetBlendColor, @DLParser_SetPrimColor, @DLParser_SetEnvColor,
|
|
@DLParser_SetCombine, @DLParser_SetTImg, @DLParser_SetZImg, @DLParser_SetCImg]
|
|
return
|
|
|
|
|
|
|
|
makeUcodeData: () ->
|
|
@ucodeData = [
|
|
#ucode, crc_size, crc_800, ucode_name, non_nearclip, reject
|
|
[0, 0x150c3ce8, 0x150c3ce8, "RSP SW Version: 2.0D, 04-01-96"], # Super Mario 64
|
|
[4, 0x2b94276f, 0x2b94276f, "RSP SW Version: 2.0D, 04-01-96"], # Wave Race 64 (v1.0)
|
|
[16,0xb1870454, 0xb1870454, "RSP SW Version: 2.0D, 04-01-96"], # Star Wars - Shadows of the Empire (v1.0),
|
|
[0, 0x51671ae4, 0x51671ae4, "RSP SW Version: 2.0D, 04-01-96"], # Pilot Wings 64,
|
|
[0, 0x67b5ac55, 0x67b5ac55, "RSP SW Version: 2.0D, 04-01-96"], # Wibble,
|
|
[0, 0x64dc8104, 0x64dc8104, "RSP SW Version: 2.0D, 04-01-96"], # Dark Rift,
|
|
[0, 0x309f363d, 0x309f363d, "RSP SW Version: 2.0D, 04-01-96"], # Killer Instinct Gold,
|
|
[0, 0xfcb57e57, 0xfcb57e57, "RSP SW Version: 2.0D, 04-01-96"], # Blast Corps,
|
|
[0, 0xb420f35a, 0xb420f35a, "RSP SW Version: 2.0D, 04-01-96"], # Blast Corps,
|
|
[0, 0x6e26c1df, 0x7c98e9c2, "RSP SW Version: 2.0D, 04-01-96"],
|
|
[2, 0xc02ac7bc, 0xc02ac7bc, "RSP SW Version: 2.0G, 09-30-96"], # GoldenEye 007,
|
|
[0, 0xe5fee3bc, 0xe5fee3bc, "RSP SW Version: 2.0G, 09-30-96"], # Aero Fighters Assault,
|
|
[8, 0xe4bb5ad8, 0x80129845, "RSP SW Version: 2.0G, 09-30-96"], # Puzzle Master 64,
|
|
[0, 0x72109ec6, 0x72109ec6, "RSP SW Version: 2.0H, 02-12-97"], # Duke Nukem 64,
|
|
[0, 0xf24a9a04, 0xf24a9a04, "RSP SW Version: 2.0H, 02-12-97"], # Tetrisphere,
|
|
[15,0x700de42e, 0x700de42e, "RSP SW Version: 2.0H, 02-12-97"], # Wipeout 64 (uses GBI1 too!),
|
|
[15,0x1b304a74, 0x1b304a74, "RSP SW Version: 2.0H, 02-12-97"], # Flying Dragon,
|
|
[15,0xe4bb5ad8, 0xa7b2f704, "RSP SW Version: 2.0H, 02-12-97"], # Silicon Valley,
|
|
[15,0xe4bb5ad8, 0x88202781, "RSP SW Version: 2.0H, 02-12-97"], # Glover,
|
|
[0, 0xe466b5bd, 0xe466b5bd, "Unknown 0xe466b5bd, 0xe466b5bd"], # Dark Rift,
|
|
[9, 0x7064a163, 0x7064a163, "Unknown 0x7064a163, 0x7064a163"], # Perfect Dark (v1.0),
|
|
[0, 0x6522df69, 0x71bd078d, "Unknown 0x6522df69, 0x71bd078d"], # Tetris
|
|
[0, 0x6522df69, 0x1b0c23a8, "Unknown 0x6522df69, 0x1b0c23a8"], # Pachinko Nichi
|
|
# GBI1
|
|
[1, 0x45ca328e, 0x45ca328e, "RSP Gfx ucode F3DLX 0.95 Yoshitaka Yasumoto Nintendo."], # Mario Kart 64,
|
|
[1, 0x98e3b909, 0x98e3b909, "RSP Gfx ucode F3DEX 0.95 Yoshitaka Yasumoto Nintendo."], # Mario Kart 64
|
|
[1, 0x5d446090, 0x5d446090, "RSP Gfx ucode F3DLP.Rej 0.96 Yoshitaka Yasumoto Nintendo.",0,1], # Jikkyou J. League Perfect Striker,
|
|
[1, 0x244f5ca3, 0x244f5ca3, "RSP Gfx ucode F3DEX 1.00 Yoshitaka Yasumoto Nintendo."], # F-1 Pole Position 64,
|
|
[1, 0x6a022585, 0x6a022585, "RSP Gfx ucode F3DEX.NoN 1.00 Yoshitaka Yasumoto Nintendo.",1], # Turok - The Dinosaur Hunter (v1.0),
|
|
[1, 0x150706be, 0x150706be, "RSP Gfx ucode F3DLX.NoN 1.00 Yoshitaka Yasumoto Nintendo.",1], # Extreme-G,
|
|
[1, 0x503f2c53, 0x503f2c53, "RSP Gfx ucode F3DEX.NoN 1.21 Yoshitaka Yasumoto Nintendo.",1], # Bomberman 64,
|
|
[1, 0xc705c37c, 0xc705c37c, "RSP Gfx ucode F3DLX 1.21 Yoshitaka Yasumoto Nintendo."], # Fighting Force 64, Wipeout 64
|
|
[1, 0xa2146075, 0xa2146075, "RSP Gfx ucode F3DLX.NoN 1.21 Yoshitaka Yasumoto Nintendo.",1], # San Francisco Rush - Extreme Racing,
|
|
[1, 0xb65aa2da, 0xb65aa2da, "RSP Gfx ucode L3DEX 1.21 Yoshitaka Yasumoto Nintendo."], # Wipeout 64,
|
|
[1, 0x0c8e5ec9, 0x0c8e5ec9, "RSP Gfx ucode F3DEX 1.21 Yoshitaka Yasumoto Nintendo."], #
|
|
[1, 0xe30795f2, 0xa53df3c4, "RSP Gfx ucode F3DLP.Rej 1.21 Yoshitaka Yasumoto Nintendo.",0,1],
|
|
[1, 0xaebeda7d, 0xaebeda7d, "RSP Gfx ucode F3DLX.Rej 1.21 Yoshitaka Yasumoto Nintendo.",0,1], # Jikkyou World Soccer 3,
|
|
[1, 0x0c8e5ec9, 0x0c8e5ec9, "RSP Gfx ucode F3DEX 1.23 Yoshitaka Yasumoto Nintendo" ], # Wave Race 64 (Rev. 2) - Shindou Rumble Edition (JAP)
|
|
[1, 0xc705c37c, 0xc705c37c, "RSP Gfx ucode F3DLX 1.23 Yoshitaka Yasumoto Nintendo."], # GT
|
|
[1, 0x2a61350d, 0x2a61350d, "RSP Gfx ucode F3DLX 1.23 Yoshitaka Yasumoto Nintendo."], # Toy Story2
|
|
[1, 0x0c8e5ec9, 0x0c8e5ec9, "RSP Gfx ucode F3DEX 1.23 Yoshitaka Yasumoto Nintendo."], # Wave Race 64 Shindou Edition
|
|
[12,0xfc6529aa, 0xfc6529aa, "RSP Gfx ucode F3DEX 1.23 Yoshitaka Yasumoto Nintendo."], # Superman - The Animated Series,
|
|
[1, 0xa56cf996, 0xa56cf996, "RSP Gfx ucode L3DEX 1.23 Yoshitaka Yasumoto Nintendo."], # Flying Dragon,
|
|
[1, 0xcc83b43f, 0xcc83b43f, "RSP Gfx ucode F3DEX.NoN 1.23 Yoshitaka Yasumoto Nintendo.",1], # AeroGauge,
|
|
[1, 0xca8927a0, 0xca8927a0, "RSP Gfx ucode F3DLX.Rej 1.23 Yoshitaka Yasumoto Nintendo.",0,1], # Puzzle Bobble 64,
|
|
[1, 0x25689c75, 0xbe481ae8, "RSP Gfx ucode F3DLP.Rej 1.23 Yoshitaka Yasumoto Nintendo.",0,1],
|
|
[1, 0xd2d747b7, 0xd2d747b7, "RSP Gfx ucode F3DLX.NoN 1.23 Yoshitaka Yasumoto Nintendo.",1], # Penny Racers,
|
|
[1, 0xa849c858, 0x5bd32b5a, "RSP Gfx ucode F3DTEX/A 1.23 Yoshitaka Yasumoto Nintendo."], # Tamagotchi
|
|
[7, 0xecd8b772, 0xecd8b772, "RSP Gfx ucode S2DEX 1.06 Yoshitaka Yasumoto Nintendo."], # Yoshi's Story,
|
|
[7, 0xf59132f5, 0xf59132f5, "RSP Gfx ucode S2DEX 1.07 Yoshitaka Yasumoto Nintendo."], # Bakuretsu Muteki Bangaioh,
|
|
[7, 0x961dd811, 0x961dd811, "RSP Gfx ucode S2DEX 1.03 Yoshitaka Yasumoto Nintendo."], # GT
|
|
[5, 0x3e083afa, 0x722f97cc, "RSP Gfx ucode F3DEX.NoN fifo 2.03 Yoshitaka Yasumoto 1998 Nintendo.",1], # F-Zero X,
|
|
[5, 0xa8050bd1, 0xa8050bd1, "RSP Gfx ucode F3DEX fifo 2.03 Yoshitaka Yasumoto 1998 Nintendo."], # F-Zero X,
|
|
[5, 0x4e8055f0, 0x4e8055f0, "RSP Gfx ucode F3DLX.Rej fifo 2.03 Yoshitaka Yasumoto 1998 Nintendo.",0,1], # F-Zero X,
|
|
[5, 0xabf001f5, 0xabf001f5, "RSP Gfx ucode F3DFLX.Rej fifo 2.03F Yoshitaka Yasumoto 1998 Nintendo.",0,1], # F-Zero X,
|
|
[5, 0xadb4b686, 0xadb4b686, "RSP Gfx ucode F3DEX fifo 2.04 Yoshitaka Yasumoto 1998 Nintendo."], # Top Gear Rally 2,
|
|
[5, 0x779e2a9b, 0x779e2a9b, "RSP Gfx ucode F3DEX.NoN fifo 2.04 Yoshitaka Yasumoto 1998 Nintendo.",1], # California Speed,
|
|
[5, 0xa8cb3e09, 0xa8cb3e09, "RSP Gfx ucode L3DEX fifo 2.04 Yoshitaka Yasumoto 1998 Nintendo."], # In-Fisherman Bass Hunter 64,
|
|
[5, 0x2a1341d6, 0x2a1341d6, "RSP Gfx ucode F3DEX fifo 2.04H Yoshitaka Yasumoto 1998 Nintendo."], # Kirby 64 - The Crystal Shards,
|
|
[5, 0x3e083afa, 0x89a8e0ed, "RSP Gfx ucode F3DEX.NoN fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo.",1], # Carmageddon 64 (uncensored),
|
|
[5, 0x4964b75d, 0x4964b75d, "RSP Gfx ucode F3DEX.NoN fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo.",1],
|
|
[5, 0x39e3e95a, 0x39e3e95a, "RSP Gfx ucode F3DEX fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo."], # Knife Edge - Nose Gunner,
|
|
[5, 0xd2913522, 0xd2913522, "RSP Gfx ucode F3DAM fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo."], # Hey You, Pikachu!,
|
|
[5, 0x3e083afa, 0xc998443f, "RSP Gfx ucode F3DEX xbus 2.05 Yoshitaka Yasumoto 1998 Nintendo."], #Triple play
|
|
[5, 0xf4184a7d, 0xf4184a7d, "RSP Gfx ucode F3DEX fifo 2.06 Yoshitaka Yasumoto 1998 Nintendo."], # Hey You, Pikachu!,
|
|
[5, 0x595a88de, 0x595a88de, "RSP Gfx ucode F3DEX.Rej fifo 2.06 Yoshitaka Yasumoto 1998 Nintendo.",0,1], # Bio Hazard 2,
|
|
[5, 0x0259f764, 0x0259f764, "RSP Gfx ucode F3DLX.Rej fifo 2.06 Yoshitaka Yasumoto 1998 Nintendo.",0,1], # Mario Party,
|
|
[5, 0xe1a5477a, 0xe1a5477a, "RSP Gfx ucode F3DEX.NoN xbus 2.06 Yoshitaka Yasumoto 1998 Nintendo.",1], # Command & Conquer,
|
|
[5, 0x4cfa0a19, 0x4cfa0a19, "RSP Gfx ucode F3DZEX.NoN fifo 2.06H Yoshitaka Yasumoto 1998 Nintendo.",1], # The Legend of Zelda - Ocarina of Time (v1.0),
|
|
[5, 0x2cbd9514, 0x5f40b9f5, "RSP Gfx ucode F3DZEX.NoN fifo 2.06H Yoshitaka Yasumoto 1998 Nintendo.",1],
|
|
[5, 0x3e083afa, 0x882680f4, "RSP Gfx ucode L3DEX fifo 2.07 Yoshitaka Yasumoto 1998 Nintendo."], # Polaris Sno
|
|
[5, 0xdeb1cac0, 0xdeb1cac0, "RSP Gfx ucode F3DEX.NoN fifo 2.07 Yoshitaka Yasumoto 1998 Nintendo.",1], # Knockout Kings 2000,
|
|
[5, 0xf4184a7d, 0xf4184a7d, "RSP Gfx ucode F3DEX fifo 2.07 Yoshitaka Yasumoto 1998 Nintendo."], # Xena Warrior Princess - Talisman of Fate, Army Men - Air Combat, Destruction Derby
|
|
[5, 0x4b013e60, 0x4b013e60, "RSP Gfx ucode F3DEX xbus 2.07 Yoshitaka Yasumoto 1998 Nintendo."], # Lode Runner 3-D,
|
|
[5, 0xd1a63836, 0xd1a63836, "RSP Gfx ucode L3DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo."], # Hey You, Pikachu!,
|
|
[5, 0x97193667, 0x97193667, "RSP Gfx ucode F3DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo."], # Top Gear Hyper-Bike,
|
|
[5, 0x92149ba8, 0x92149ba8, "RSP Gfx ucode F3DEX fifo 2.08 Yoshitaka Yasumoto/Kawasedo 1999."], # Paper Mario,
|
|
[5, 0xae0fb88f, 0xae0fb88f, "RSP Gfx ucode F3DEX xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo."], # WWF WrestleMania 2000,
|
|
[5, 0xc572f368, 0xc572f368, "RSP Gfx ucode F3DLX.Rej xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo."], # WWF No Mercy,
|
|
[5, 0x3e083afa, 0x74252492, "RSP Gfx ucode F3DEX.NoN xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo.",1],
|
|
[5, 0x9c2edb70, 0xea98e740, "RSP Gfx ucode F3DEX.NoN fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",1], # LEGO Racers,
|
|
[5, 0x79e004a6, 0x79e004a6, "RSP Gfx ucode F3DLX.Rej fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",0,1], # Mario Party 2,
|
|
[5, 0xaa6ab3ca, 0xaa6ab3ca, "RSP Gfx ucode F3DEX.Rej fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",0,1], # V-Rally Edition 99,
|
|
[5, 0x2c597e0f, 0x2c597e0f, "RSP Gfx ucode F3DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo."], # Cruis'n Exotica,
|
|
[10, 0x4e5f3e3b, 0x4e5f3e3b,"RSP Gfx ucode F3DEXBG.NoN fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo.",1], # Conker The Bad Fur Day
|
|
[5, 0x61f31862, 0x61f31862, "RSP Gfx ucode F3DEX.NoN fifo 2.08H Yoshitaka Yasumoto 1999 Nintendo.",1], # Pokemon Snap,
|
|
[5, 0x005f5b71, 0x005f5b71, "RSP Gfx ucode F3DZEX.NoN fifo 2.08I Yoshitaka Yasumoto/Kawasedo 1999.",1], # The Legend of Zelda 2 - Majora's Mask,
|
|
[3, 0x41839d1e, 0x41839d1e, "RSP Gfx ucode S2DEX fifo 2.05 Yoshitaka Yasumoto 1998 Nintendo."], # Chou Snobow Kids,
|
|
[3, 0x2cbd9514, 0xc639dbb9, "RSP Gfx ucode S2DEX xbus 2.06 Yoshitaka Yasumoto 1998 Nintendo."],
|
|
[3, 0xec89e273, 0xec89e273, "RSP Gfx ucode S2DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo."], # V-Rally Edition 99,
|
|
[3, 0x9429b7d6, 0x9429b7d6, "RSP Gfx ucode S2DEX xbus 2.08 Yoshitaka Yasumoto 1999 Nintendo."], # Star Craft,
|
|
# {14,0x5a72397b, 0xec89e273, "RSP Gfx ucode S2DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo."], # OgreBattle Background,
|
|
[3, 0x2cbd9514, 0xec89e273, "RSP Gfx ucode S2DEX fifo 2.08 Yoshitaka Yasumoto 1999 Nintendo."], # Zelda MM,
|
|
[6, 0x6aef74f8, 0x6aef74f8, "Unknown 0x6aef74f8, 0x6aef74f8"], # Diddy Kong Racing (v1.0),
|
|
[6, 0x4c4eead8, 0x4c4eead8, "Unknown 0x4c4eead8, 0x4c4eead8"], # Diddy Kong Racing (v1.1),
|
|
[1, 0xed421e9a, 0xed421e9a, "Unknown 0xed421e9a, 0xed421e9a"], # Kuiki Uhabi Suigo,
|
|
[5, 0x37751932, 0x55c0fd25, "Unknown 0x37751932, 0x55c0fd25"], # Bio Hazard 2,
|
|
[11,0xbe0b83e7, 0xbe0b83e7,"Unknown 0xbe0b83e7, 0xbe0b83e7"], # Jet Force Gemini,
|
|
[17, 0x02e882cf, 0x2ad17281, "Unknown 0x02e882cf, 0x2ad17281"], # Indiana Jones,
|
|
[17, 0x1f7d9118, 0xdab2199b, "Unknown 0x1f7d9118, 0xdab2199b"], # Battle Naboo,
|
|
[17, 0x74583614, 0x74583614, "Unknown 0x74583614, 0x74583614"], # Star Wars - Rogue Squadron,
|
|
[17, 0xe37e2f49, 0x1eb63fd8, "Unknown 0xe37e2f49, 0x1eb63fd8"], # Star Wars - Rogue Squadron,
|
|
[17, 0x8ce1af3d, 0xb2760ea2, "Unknown 0x8ce1af3d, 0xb2760ea2"], # Star Wars - Rogue Squadron,
|
|
[18, 0x7b685972, 0x57b8095a, "Unknown 0x7b685972, 0x57b8095a"], # World Driver Championship
|
|
[18, 0xe92dbb9b, 0x57b8095a, "Unknown 0xe92dbb9b, 0x57b8095a"], # World Driver Championship
|
|
[18, 0xe6c9acc1, 0x65f80845, "Unknown 0xe6c9acc1, 0x65f80845"], # World Driver Championship
|
|
[18, 0x6522df69, 0x720b88a0, "Unknown 0x6522df69, 0x720b88a0"], # World Driver Championship
|
|
[18, 0x6522df69, 0xf1e8ba9e, "Unknown 0x6522df69, 0xf1e8ba9e"], # World Driver Championship
|
|
[19, 0xa486bed3, 0xa486bed3, "Unknown 0xa486bed3, 0xa486bed3"], # Last Legion UX,
|
|
[19, 0x6b519381, 0xfebacfd8, "Unknown in Toukan Road"], # I don't know which ucode
|
|
[20, 0x6d2a01b1, 0x6d2a01b1, "RSP Gfx ucode ZSortp 0.33 Yoshitaka Yasumoto Nintendo."], # Mia Hamm Soccer 64,
|
|
]
|
|
|
|
makeCRCTable: () ->
|
|
crcTable = []
|
|
# terms of polynomial defining this crc (except x^32):
|
|
p = [0,1,2,4,5,7,8,10,11,12,16,22,23,26]
|
|
|
|
# make exclusive-or pattern from polynomial (0xedb88320L)
|
|
poly = 0 # polynomial exclusive-or pattern
|
|
for n in [0...p.length]
|
|
poly |= 1 << (31 - p[n])
|
|
|
|
c = 0
|
|
for n in [0...256]
|
|
c = n
|
|
for k in [0...8]
|
|
if c & 1
|
|
c = (poly ^ (c >>> 1))>>>0
|
|
else
|
|
c >>>= 1
|
|
crcTable[n] = c
|
|
crcTable
|
|
|
|
computeCRC32: (crc, base, len) ->
|
|
crc ^= 0xffffffff
|
|
crc >>>= 0
|
|
|
|
# the crcs hat 1964 made were based on little-endian memory layout, so
|
|
# for big endian and byteCompatibility mode, we need to ^3 to each byte.
|
|
if @core.useByteCompatibilityMode is true or @core.isLittleEndian is 0
|
|
while (len > 0)
|
|
crc = (@crcTable[(crc ^ @core.memory.u8[base^3]) & 0xff] ^ (crc >>> 8))>>>0
|
|
base++
|
|
len--
|
|
else
|
|
while (len > 0)
|
|
crc = (@crcTable[(crc ^ @core.memory.u8[base]) & 0xff] ^ (crc >>> 8))>>>0
|
|
base++
|
|
len--
|
|
return (crc ^ 0xffffffff)>>>0
|
|
|
|
DLParser_CheckUCode: (start, dStart, size, dSize) ->
|
|
ucode = -1
|
|
base = dStart & 0x1fffffff
|
|
str = ""
|
|
if base < @core.currentRdramSize+0x1000
|
|
for i in [0...(0x1000-2)]
|
|
# check for 'R' 'S' 'P' ("RSP") ascii 82, 83, 80
|
|
if @core.memory.readRdram8(base + i) is 82 and @core.memory.readRdram8(base + i + 1) is 83 and @core.memory.readRdram8(base + i + 2) is 80
|
|
#concat chars (32 is ascii for space character)
|
|
while @core.memory.readRdram8(base + i) >= 32
|
|
str += String.fromCharCode(@core.memory.readRdram8(base + i))
|
|
i++
|
|
crcSize = @computeCRC32 0, start, 8
|
|
crc800 = @computeCRC32 0, start, 0x800
|
|
ucode = @DLParser_IdentifyUcode crc800
|
|
break
|
|
if ucode != -1
|
|
console.log "Detected microcode " + ucode
|
|
else
|
|
console.log "Unknown ucode. Using microcode #5"
|
|
ucode = 5
|
|
return ucode
|
|
|
|
RDP_SetUcodeMap: (ucode) ->
|
|
switch ucode
|
|
when 1
|
|
@microcodeMap0[4] = @RSP_GBI1_Vtx
|
|
@microcodeMap0[9] = @RSP_GBI1_Sprite2DBase
|
|
@microcodeMap0[0xaf] = @RSP_GBI1_LoadUCode
|
|
@microcodeMap0[0xb0] = @RSP_GBI1_BranchZ
|
|
@microcodeMap0[0xb1] = @RSP_GBI1_Tri2
|
|
@microcodeMap0[0xb2] = @RSP_GBI1_ModifyVtx
|
|
@microcodeMap0[0xc1] = @RSP_S2DEX_SPObjLoadTxtr_Ucode1
|
|
return
|
|
|
|
DLParser_IdentifyUcode: (crc800) ->
|
|
for i in [0...@ucodeData.length]
|
|
#get crc_800 field
|
|
if @ucodeData[i][2] is crc800
|
|
#return ucode field
|
|
return @ucodeData[i][0]
|
|
return -1 # not found
|
|
|
|
callBind: (fn, me) ->
|
|
->
|
|
fn.call me
|
|
|
|
processDisplayList: ->
|
|
if @core.showFB is true
|
|
@initBuffers()
|
|
@core.webGL.show3D()
|
|
@core.showFB = false
|
|
@resetState()
|
|
|
|
wireframe = document.getElementById("wireframe")
|
|
@core.settings.wireframe = false
|
|
@core.settings.wireframe = true if wireframe isnt null and wireframe.checked
|
|
|
|
|
|
@core.webGL.beginDList()
|
|
@dlParserProcess()
|
|
|
|
#this.core.interrupts.triggerDPInterrupt(0, false);
|
|
@core.interrupts.delayNextInterrupt = true #don't process immediately
|
|
@core.interrupts.triggerDPInterrupt 0, false
|
|
return
|
|
|
|
videoLog: (msg) ->
|
|
#console.log msg
|
|
return
|
|
|
|
checkUcode: ->
|
|
if @currentMicrocodeMap is undefined
|
|
|
|
tUcode = @core.memory.getInt32(@core.memory.spMemUint8Array, consts.TASK_MICROCODE, @core.memory.spMemUint32Array)
|
|
tUcodeData = @core.memory.getInt32(@core.memory.spMemUint8Array, consts.TASK_MICROCODE_DATA, @core.memory.spMemUint32Array)
|
|
tUcodeSize = @core.memory.getInt32(@core.memory.spMemUint8Array, consts.TASK_MICROCODE_SIZE, @core.memory.spMemUint32Array)
|
|
tUcodeDataSize = @core.memory.getInt32(@core.memory.spMemUint8Array, consts.TASK_MICROCODE_DATA_SIZE, @core.memory.spMemUint32Array)
|
|
|
|
@ucode = @DLParser_CheckUCode tUcode, tUcodeData, tUcodeSize, tUcodeDataSize
|
|
@RDP_SetUcodeMap @ucode
|
|
@vertexMult = 1.0 / @vertexMultVals[@ucode]
|
|
@currentMicrocodeMap = @microcodeMap0 # to only execute this once
|
|
return
|
|
|
|
dlParserProcess: ->
|
|
|
|
@checkUcode()
|
|
|
|
@dlistStackPointer = 0
|
|
@dlistStack[@dlistStackPointer].pc = @core.memory.getInt32(@core.memory.spMemUint8Array, consts.TASK_DATA_PTR, @core.memory.spMemUint32Array)>>>0
|
|
@dlistStack[@dlistStackPointer].countdown = consts.MAX_DL_COUNT
|
|
|
|
#see RSP_Parser.cpp
|
|
#TODO: purge old textures
|
|
#TODO: stats
|
|
#TODO: force screen clear
|
|
#TODO: set vi scales
|
|
@renderReset()
|
|
|
|
#TODO: render reset
|
|
#TODO: begin rendering
|
|
#TODO: set viewport
|
|
#TODO: set fill mode
|
|
aa = 10000
|
|
while @dlistStackPointer >= 0 and aa > 0
|
|
aa--
|
|
pc = @dlistStack[@dlistStackPointer].pc
|
|
cmd = @getCommand(pc)
|
|
func = @currentMicrocodeMap[cmd]
|
|
@dlistStack[@dlistStackPointer].pc += 8
|
|
func.call this, pc
|
|
if @dlistStackPointer >= 0
|
|
@dlistStack[@dlistStackPointer].countdown -= 1
|
|
@dlistStackPointer -= 1 if @dlistStack[@dlistStackPointer].countdown < 0
|
|
|
|
if aa <= 0
|
|
alert "Too many dlist calls"
|
|
@core.terminate = true
|
|
return
|
|
|
|
#TODO: end rendering
|
|
RDP_GFX_PopDL: ->
|
|
@dlistStackPointer -= 1
|
|
return
|
|
|
|
RSP_RDP_Nothing: (pc) ->
|
|
#@videoLog "RSP RDP NOTHING"
|
|
#@dlistStackPointer -= 1
|
|
return
|
|
|
|
RSP_GBI1_MoveMem: (pc) ->
|
|
type = @getGbi1Type(pc)
|
|
seg = @getGbi0DlistAddr(pc)
|
|
addr = @getRspSegmentAddr(seg)
|
|
switch type
|
|
when consts.RSP_GBI1_MV_MEM_VIEWPORT
|
|
@RSP_MoveMemViewport addr
|
|
#case RSP_GBI1_MV_MEM_LOOKATY:
|
|
#break;
|
|
#case RSP_GBI1_MV_MEM_LOOKATX:
|
|
#break;
|
|
when consts.RSP_GBI1_MV_MEM_L0, consts.RSP_GBI1_MV_MEM_L1, consts.RSP_GBI1_MV_MEM_L2, consts.RSP_GBI1_MV_MEM_L3, consts.RSP_GBI1_MV_MEM_L4, consts.RSP_GBI1_MV_MEM_L5, consts.RSP_GBI1_MV_MEM_L6, consts.RSP_GBI1_MV_MEM_L7
|
|
dwLight = (type-consts.RSP_GBI1_MV_MEM_L0)/2
|
|
@RSP_MoveMemLight dwLight, addr, pc
|
|
when consts.RSP_GBI1_MV_MEM_MATRIX1
|
|
@RSP_GFX_Force_Matrix pc
|
|
return
|
|
|
|
RSP_GFX_Force_Matrix: (pc) ->
|
|
@RSP_GBI0_Mtx pc
|
|
|
|
RSP_MoveMemViewport: (addr) ->
|
|
@videoLog "RSP_MoveMemViewport"
|
|
|
|
if addr + 16 >= @core.currentRdramSize
|
|
console.warn "viewport addresses beyond mem size"
|
|
return
|
|
|
|
scale = new Float32Array(4)
|
|
trans = new Float32Array(4)
|
|
|
|
scale[0] = @getShort addr+0*2
|
|
scale[1] = @getShort addr+1*2
|
|
scale[2] = @getShort addr+2*2
|
|
scale[3] = @getShort addr+3*2
|
|
|
|
trans[0] = @getShort addr+4*2
|
|
trans[1] = @getShort addr+5*2
|
|
trans[2] = @getShort addr+6*2
|
|
trans[3] = @getShort addr+7*2
|
|
|
|
centerX = trans[0] / 4.0
|
|
centerY = trans[1] / 4.0
|
|
@n64ViewportWidth = scale[0] / 4.0
|
|
@n64ViewportHeight = scale[1] / 4.0
|
|
|
|
@n64ViewportWidth = -@n64ViewportWidth if @n64ViewportWidth < 0
|
|
@n64ViewportHeight = -@n64ViewportHeight if @n64ViewportHeight < 0
|
|
@n64ViewportLeft = centerX - @n64ViewportWidth
|
|
@n64ViewportTop = centerY - @n64ViewportHeight
|
|
@n64ViewportRight = centerX + @n64ViewportWidth
|
|
@n64ViewportBottom = centerY + @n64ViewportHeight
|
|
|
|
maxZ = 0x3FF
|
|
|
|
#@setViewPort left, top, right, bottom, maxZ
|
|
|
|
return
|
|
|
|
RSP_GBI1_SpNoop: (pc) ->
|
|
#@videoLog "RSP_GBI1_SpNoop"
|
|
return
|
|
|
|
RSP_GBI1_Reserved: (pc) ->
|
|
#@videoLog "RSP_GBI1_Reserved"
|
|
return
|
|
|
|
setProjection: (mat, bPush, bReplace) ->
|
|
if bPush is true
|
|
if @gRSP.projectionMtxTop >= (@RICE_MATRIX_STACK - 1)
|
|
@gRSP.bMatrixIsUpdated = true
|
|
@inverseTransposeCalculated = false
|
|
return
|
|
@gRSP.projectionMtxTop += 1
|
|
# We should store the current projection matrix...
|
|
if bReplace
|
|
# Load projection matrix
|
|
mat4.set mat, @gRSP.projectionMtxs[@gRSP.projectionMtxTop]
|
|
else
|
|
mat4.multiply @gRSP.projectionMtxs[@gRSP.projectionMtxTop - 1], mat, @gRSP.projectionMtxs[@gRSP.projectionMtxTop]
|
|
else
|
|
if bReplace
|
|
# Load projection matrix
|
|
mat4.set mat, @gRSP.projectionMtxs[@gRSP.projectionMtxTop]
|
|
else
|
|
mat4.multiply @gRSP.projectionMtxs[@gRSP.projectionMtxTop], mat, @gRSP.projectionMtxs[@gRSP.projectionMtxTop]
|
|
@gRSP.bMatrixIsUpdated = true
|
|
@inverseTransposeCalculated = false
|
|
|
|
#hack to show Mario's head (as an ortho projection. This if/else is wrong.
|
|
if @gRSP.projectionMtxs[@gRSP.projectionMtxTop][14] > 0
|
|
mat4.ortho -1024, 1024, -1024, 1024, -1023.0, 1024.0, @gRSP.projectionMtxs[@gRSP.projectionMtxTop]
|
|
else
|
|
mat4.ortho -1, 1, -1, 1, -1, 1, 1.0, 1024.0, this.gRSP.projectionMtxs[this.gRSP.projectionMtxTop]
|
|
return
|
|
|
|
setWorldView: (mat, bPush, bReplace) ->
|
|
if bPush is true
|
|
if @gRSP.modelViewMtxTop >= (@RICE_MATRIX_STACK - 1)
|
|
@gRSP.bMatrixIsUpdated = true
|
|
@inverseTransposeCalculated = false
|
|
return
|
|
@gRSP.modelViewMtxTop += 1
|
|
if bReplace
|
|
# Load modelView matrix
|
|
mat4.set mat, @gRSP.modelviewMtxs[@gRSP.modelViewMtxTop]
|
|
else # Multiply modelView matrix
|
|
mat4.multiply @gRSP.modelviewMtxs[@gRSP.modelViewMtxTop - 1], mat, @gRSP.modelviewMtxs[@gRSP.modelViewMtxTop]
|
|
else # NoPush
|
|
if bReplace
|
|
# Load modelView matrix
|
|
mat4.set mat, @gRSP.modelviewMtxs[@gRSP.modelViewMtxTop]
|
|
else
|
|
# Multiply modelView matrix
|
|
mat4.multiply @gRSP.modelviewMtxs[@gRSP.modelViewMtxTop], mat, @gRSP.modelviewMtxs[@gRSP.modelViewMtxTop]
|
|
@gRSP.bMatrixIsUpdated = true
|
|
@inverseTransposeCalculated = false
|
|
return
|
|
|
|
RSP_GBI0_Mtx: (pc) ->
|
|
addr = undefined
|
|
seg = @getGbi0DlistAddr(pc)
|
|
addr = @getRspSegmentAddr(seg)
|
|
#@videoLog "RSP_GBI0_Mtx addr: " + dec2hex(addr)
|
|
@loadMatrix addr
|
|
if @gbi0isProjectionMatrix pc
|
|
@setProjection @matToLoad, @gbi0PushMatrix(pc), @gbi0LoadMatrix(pc)
|
|
else
|
|
@setWorldView @matToLoad, @gbi0PushMatrix(pc), @gbi0LoadMatrix(pc)
|
|
|
|
@renderStateChanged = true
|
|
return
|
|
|
|
loadMatrix: (addr) ->
|
|
# todo: port and probably log warning message if true
|
|
if (addr + 64 > @core.currentRdramSize)
|
|
console.warn "loading matrix beyond ram size"
|
|
return
|
|
i = undefined
|
|
j = undefined
|
|
a = addr
|
|
b = undefined
|
|
k = 0
|
|
i = 0
|
|
`const u8 = this.core.memory.u8`
|
|
`const matToLoad = this.matToLoad`
|
|
while i < 4
|
|
j = 0
|
|
while j < 4
|
|
# 0.0000152587890625 is 1.0/65536.0
|
|
matToLoad[k] = ((u8[a] << 24 | u8[a + 1] << 16 | u8[a + 32] << 8 | u8[a + 32 + 1])>>0) * 0.0000152587890625
|
|
k += 1
|
|
a += 2
|
|
j += 1
|
|
i += 1
|
|
return
|
|
|
|
#tile info.
|
|
DLParser_SetTImg: (pc) ->
|
|
@texImg.format = @getTImgFormat(pc)
|
|
@texImg.size = @getTImgSize(pc)
|
|
@texImg.width = @getTImgWidth(pc) + 1
|
|
@texImg.addr = @getTImgAddr(pc)
|
|
@texImg.bpl = @texImg.width << @texImg.size >> 1
|
|
@texImg.changed = true #no texture cache
|
|
#console.log "SetTImg: Format:"+ @texImg.format + " Size:" + @texImg.size + " Width: "+ @texImg.width
|
|
return
|
|
|
|
#this.videoLog('Texture: format=' + this.texImg.format + ' size=' + this.texImg.size + ' ' + 'width=' + this.texImg.width + ' addr=' + this.texImg.addr + ' bpl=' + this.texImg.bpl);
|
|
|
|
RSP_GBI0_Vtx: (pc) ->
|
|
num = @getGbi0NumVertices(pc) + 1
|
|
v0 = @getGbi0Vertex0(pc)
|
|
seg = @getGbi0DlistAddr(pc)
|
|
addr = @getRspSegmentAddr(seg)
|
|
num = 32 - v0 if (v0 + num) > @MAX_VERTICES
|
|
|
|
#Check that the address is valid
|
|
if (addr + num*16) > @core.currentRdramSize
|
|
console.warn "vertex is beyond ram size"
|
|
else
|
|
@processVertexData addr, v0, num
|
|
return
|
|
|
|
RSP_GBI1_Vtx: (pc) ->
|
|
num = @getGbi1NumVertices(pc)
|
|
v0 = @getGbi1Vertex0(pc)
|
|
seg = @getGbi0DlistAddr(pc)
|
|
addr = @getRspSegmentAddr(seg)
|
|
return if (v0 + num) > @MAX_VERTICES
|
|
|
|
#Check that the address is valid
|
|
if addr > @core.currentRdramSize
|
|
console.warn "vertex is beyond ram size"
|
|
else
|
|
@processVertexData addr, v0, num
|
|
return
|
|
|
|
RSP_GBI1_Sprite2DBase: (pc) ->
|
|
@videoLog "todo: RSP_GBI1_Sprite2DBase"
|
|
return
|
|
|
|
RSP_GBI1_LoadUCode: (pc) ->
|
|
@videoLog "todo: RSP_GBI1_LoadUCode"
|
|
return
|
|
|
|
RSP_GBI1_BranchZ: (pc) ->
|
|
@videoLog "todo: RSP_GBI1_BranchZ"
|
|
return
|
|
|
|
RSP_GBI1_Tri2: (pc) ->
|
|
mult = @vertexMult
|
|
v0 = @getGbi0Tri1V0(pc) * mult
|
|
v1 = @getGbi0Tri1V1(pc) * mult
|
|
v2 = @getGbi0Tri1V2(pc) * mult
|
|
#flag = @getGbi0Tri1Flag(pc)
|
|
didSucceed = @prepareTriangle v0, v1, v2
|
|
|
|
if didSucceed is false
|
|
return
|
|
|
|
v3 = @getGbi1Tri2V3(pc) * mult
|
|
v4 = @getGbi1Tri2V4(pc) * mult
|
|
v5 = @getGbi1Tri2V5(pc) * mult
|
|
#flag = @getGbi0Tri1Flag(pc)
|
|
didSucceed = @prepareTriangle v3, v4, v5
|
|
|
|
if didSucceed is false
|
|
return
|
|
|
|
pc = @dlistStack[@dlistStackPointer].pc
|
|
cmd = @getCommand(pc)
|
|
func = @currentMicrocodeMap[cmd]
|
|
if func is @RSP_GBI1_Tri2
|
|
return #loops until not tri2, then it will drawScene
|
|
|
|
if @renderStateChanged is true
|
|
@drawScene false, @activeTile
|
|
return
|
|
|
|
RSP_GBI1_ModifyVtx: (pc) ->
|
|
type = @getGbi1Type(pc)
|
|
vtx = (@getWord0(pc) & 0xFFFF) >>> 1
|
|
value = @getWord1(pc)
|
|
|
|
if vtx > 80
|
|
return
|
|
|
|
switch type
|
|
when consts.RSP_MV_WORD_OFFSET_POINT_RGBA, consts.RSP_MV_WORD_OFFSET_POINT_XYSCREEN, consts.RSP_MV_WORD_OFFSET_POINT_ZSCREEN, consts.RSP_MV_WORD_OFFSET_POINT_ST
|
|
@modifyVertexInfo type, vtx, value
|
|
|
|
return
|
|
|
|
RSP_S2DEX_SPObjLoadTxtr_Ucode1: (pc) ->
|
|
@videoLog "todo: RSP_S2DEX_SPObjLoadTxtr_Ucode1"
|
|
return
|
|
|
|
processLights: (vo, i, a, sMult, tMult) ->
|
|
`const n = this.normalMat`
|
|
o = 0
|
|
vo |= 0
|
|
i |= 0
|
|
while i < 0
|
|
v = @N64VertexList[vo+i]
|
|
n[0] = @getVertexNormalX a
|
|
i += 1
|
|
n[1] = @getVertexNormalY a
|
|
n[2] = @getVertexNormalZ a
|
|
#n[3] = 1.0
|
|
|
|
tempVec3 = new Float32Array(@tempVec3Buffer, o)
|
|
v.u = @getVertexS(a) * sMult
|
|
v.w = @getVertexW(a)
|
|
mat4.multiplyVec3 @modelViewTransposedInverse, n, tempVec3
|
|
v.y = @getVertexY(a)
|
|
v.z = @getVertexZ(a)
|
|
vect = vec3.normalize tempVec3
|
|
v.v = @getVertexT(a) * tMult
|
|
v.x = @getVertexX(a)
|
|
@lightVertex vect, v
|
|
a += 16
|
|
o += 12
|
|
return
|
|
|
|
processShades: (vo, i, a, sMult, tMult) ->
|
|
while i < 0
|
|
v = @N64VertexList[vo+i]
|
|
v.w = @getVertexW(a)
|
|
v.x = @getVertexX(a)
|
|
v.y = @getVertexY(a)
|
|
i += 1
|
|
v.u = @getVertexS(a) * sMult
|
|
v.z = @getVertexZ(a)
|
|
v.r = @getVertexColorR(a)
|
|
v.g = @getVertexColorG(a)
|
|
v.b = @getVertexColorB(a)
|
|
v.a = @getVertexAlpha(a)
|
|
v.v = @getVertexT(a) * tMult
|
|
a += 16
|
|
return
|
|
|
|
processPrims: (vo, i, a, sMult, tMult) ->
|
|
while i < 0
|
|
v = @N64VertexList[vo+i]
|
|
v.w = @getVertexW(a)
|
|
v.r = @primColor[0]
|
|
v.x = @getVertexX(a)
|
|
i += 1
|
|
v.u = @getVertexS(a) * sMult
|
|
v.g = @primColor[1]
|
|
v.y = @getVertexY(a)
|
|
v.b = @primColor[2]
|
|
v.z = @getVertexZ(a)
|
|
v.a = @primColor[3]
|
|
v.v = @getVertexT(a) * tMult
|
|
a += 16
|
|
return
|
|
|
|
processVertexData: (addr, v0, num) ->
|
|
a = addr|0
|
|
i = -num
|
|
`const vo = v0+num`
|
|
`const tile = this.textureTile[this.activeTile]`
|
|
`const texWidth = (((tile.lrs >> 2) + 1) - tile.uls)|0`
|
|
`const texHeight = (((tile.lrt >> 2) + 1) - tile.ult)|0`
|
|
`const sMult = 1.0 / (texWidth<<5)`
|
|
`const tMult = 1.0 / (texHeight<<5)`
|
|
|
|
if @bLightingEnable is true
|
|
if @inverseTransposeCalculated is false and @gRSP.bMatrixIsUpdated is true
|
|
mat4.inverse @gRSP.modelviewMtxs[@gRSP.modelViewMtxTop], @modelViewInverse
|
|
mat4.transpose @modelViewInverse, @modelViewTransposedInverse
|
|
@inverseTransposeCalculated = true
|
|
@processLights vo, i, a, sMult, tMult
|
|
else if @bShade is true
|
|
@processShades vo, i, a, sMult, tMult
|
|
else
|
|
@processPrims vo, i, a, sMult, tMult
|
|
return
|
|
|
|
modifyVertexInfo: (type, vtx, value) ->
|
|
switch type
|
|
when consts.RSP_MV_WORD_OFFSET_POINT_RGBA # Modify RGBA
|
|
alert "RSP_MV_WORD_OFFSET_POINT_RGBA"
|
|
# uint32 r = (value>>24)&0xFF
|
|
# uint32 g = (value>>16)&0xFF
|
|
# uint32 b = (value>>8)&0xFF
|
|
# uint32 a = val&0xFF
|
|
# g_dwVtxDifColor[vertex] = COLOR_RGBA(r, g, b, a);
|
|
when consts.RSP_MV_WORD_OFFSET_POINT_XYSCREEN # Modify X,Y
|
|
alert "RSP_MV_WORD_OFFSET_POINT_XYSCREEN"
|
|
# uint16 nX = (uint16)(val>>16);
|
|
# short x = *((short*)&nX);
|
|
# x /= 4;
|
|
|
|
# uint16 nY = uint16(val&0xFFFF);
|
|
# short y = *((short*)&nY);
|
|
# y /= 4;
|
|
|
|
# # Should do viewport transform.
|
|
|
|
# x -= windowSetting.uViWidth/2;
|
|
# y = windowSetting.uViHeight/2-y;
|
|
|
|
# # if( options.bEnableHacks && ((*g_GraphicsInfo.VI_X_SCALE_REG)&0xF) != 0 )
|
|
# # {
|
|
# # # Tarzan
|
|
# # # I don't know why Tarzan is different
|
|
# # SetVertexXYZ(vertex, x/windowSetting.fViWidth, y/windowSetting.fViHeight, g_vecProjected[vertex].z);
|
|
# # }
|
|
# # else
|
|
# # {
|
|
# # Toy Story 2 and other games
|
|
# SetVertexXYZ(vertex, x*2/windowSetting.fViWidth, y*2/windowSetting.fViHeight, g_vecProjected[vertex].z);
|
|
# # }
|
|
|
|
when consts.RSP_MV_WORD_OFFSET_POINT_ZSCREEN # Modify C
|
|
alert "RSP_MV_WORD_OFFSET_POINT_XYSCREEN"
|
|
# int z = val>>16;
|
|
|
|
# SetVertexXYZ(vertex, g_vecProjected[vertex].x, g_vecProjected[vertex].y, (((float)z/0x03FF)+0.5f)/2.0f );
|
|
when consts.RSP_MV_WORD_OFFSET_POINT_ST # Texture
|
|
alert "RSP_MV_WORD_OFFSET_POINT_ST"
|
|
# short tu = short(val>>16);
|
|
# short tv = short(val & 0xFFFF);
|
|
# float ftu = tu / 32.0f;
|
|
# float ftv = tv / 32.0f;
|
|
# CRender::g_pRender->SetVtxTextureCoord(vertex, ftu/gRSP.fTexScaleX, ftv/gRSP.fTexScaleY);
|
|
return
|
|
|
|
DLParser_SetCImg: (pc) ->
|
|
@zColorImage.fmt = @getSetTileFmt pc
|
|
@zColorImage.siz = @getSetTileSiz pc
|
|
@zColorImage.width = @getTImgWidth(pc) + 1
|
|
seg = @getGbi0DlistAddr(pc)
|
|
@zColorImage.addr = @getRspSegmentAddr seg
|
|
return
|
|
|
|
DLParser_SetZImg: (pc) ->
|
|
@zDepthImage.fmt = @getSetTileFmt pc
|
|
@zDepthImage.siz = @getSetTileSiz pc
|
|
@zDepthImage.width = @getTImgWidth(pc) + 1
|
|
seg = @getGbi0DlistAddr(pc)
|
|
@zDepthImage.addr = @getRspSegmentAddr seg
|
|
return
|
|
|
|
#Gets new display list address
|
|
RSP_GBI0_DL: (pc) ->
|
|
param = undefined
|
|
seg = @getGbi0DlistAddr(pc)
|
|
addr = @getRspSegmentAddr(seg)
|
|
#@videoLog "dlist address = " + dec2hex(addr)
|
|
|
|
#TODO: address adjust
|
|
param = @getGbi0DlistParam(pc)
|
|
@dlistStackPointer += 1 if param is consts.RSP_DLIST_PUSH
|
|
@dlistStack[@dlistStackPointer].pc = addr
|
|
@dlistStack[@dlistStackPointer].countdown = consts.MAX_DL_COUNT
|
|
return
|
|
|
|
DLParser_SetCombine: (pc) ->
|
|
`const lo = this.getCombineLo(pc) >>> 0`
|
|
`const hi = this.getCombineHi(pc) >>> 0`
|
|
|
|
@combine[0] = (lo >> 20) & 15 # @getCombineA0(pc)
|
|
@combine[2] = (hi >> 28) & 15 # @getCombineB0(pc)
|
|
@combine[4] = (lo >> 15) & 31 # @getCombineC0(pc)
|
|
@combine[6] = (hi >> 15) & 7 # @getCombineD0(pc)
|
|
# @combineA0 = 0xFF if @combineA0 is 15
|
|
# @combineB0 = 0xFF if @combineB0 is 15
|
|
# @combineC0 = 0xFF if @combineC0 is 31
|
|
# @combineD0 = 0xFF if @combineD0 is 7
|
|
@combine[1] = (lo >> 12) & 7 # @getCombineA0a(pc)
|
|
@combine[3] = (hi >> 12) & 7 # @getCombineB0a(pc)
|
|
@combine[5] = (lo >> 9) & 7 # @getCombineC0a(pc)
|
|
@combine[7] = (hi >> 9) & 7 # @getCombineD0a(pc)
|
|
# @combineA0a = 0xFF if @combineA0a is 7
|
|
# @combineB0a = 0xFF if @combineB0a is 7
|
|
# @combineC0a = 0xFF if @combineC0a is 7
|
|
# @combineD0a = 0xFF if @combineD0a is 7
|
|
@combine[8] = (lo >> 5) & 15 # @getCombineA1(pc)
|
|
@combine[10] = (hi >> 24) & 15 # @getCombineB1(pc)
|
|
@combine[12] = lo & 31 # @getCombineC1(pc)
|
|
@combine[14] = (hi >> 6) & 7 # @getCombineD1(pc)
|
|
# @combineA1 = 0xFF if @combineA1 is 15
|
|
# @combineB1 = 0xFF if @combineB1 is 15
|
|
# @combineC1 = 0xFF if @combineC1 is 31
|
|
# @combineD1 = 0xFF if @combineD1 is 7
|
|
@combine[9] = (hi >> 21) & 7 # @getCombineA1a(pc)
|
|
@combine[11] = (hi >> 3) & 7 # @getCombineB1a(pc)
|
|
@combine[13] = (hi >> 18) & 7 # @getCombineC1a(pc)
|
|
@combine[15] = hi & 7 # @getCombineD1a(pc)
|
|
# @combineA1a = 0xFF if @combineA1a is 7
|
|
# @combineB1a = 0xFF if @combineB1a is 7
|
|
# @combineC1a = 0xFF if @combineC1a is 7
|
|
# @combineD1a = 0xFF if @combineD1a is 7
|
|
|
|
# w0 = @core.memory.u8[pc] << 24 | @core.memory.u8[pc + 1] << 16 | @core.memory.u8[pc + 2] << 8 | @core.memory.u8[pc + 3]
|
|
# w1 = @core.memory.u8[pc + 4] << 24 | @core.memory.u8[pc + 5] << 16 | @core.memory.u8[pc + 6] << 8 | @core.memory.u8[pc + 7]
|
|
|
|
#if (@combineD0 == 4)
|
|
# console.log " a0:" + @combineA0 + " b0:" + @combineB0 + " c0:" + @combineC0 + " d0:" + @combineD0 + " a0a:" + @combineA0a + " b0a:" + @combineB0a + " c0a:" + @combineC0a + " d0a:" + @combineD0a + " a1:" + @combineA1 + " b1:" + @combineB1 + " c1:" + @combineC1 + " d1:" + @combineD1 + " a1a:" + @combineA1a + " b1a:" + @combineB1a + " c1a:" + @combineC1a + " d1a:" + @combineD1a
|
|
|
|
#@videoLog "TODO: DLParser_SetCombine"
|
|
@core.webGL.setCombineUniforms this, @core.webGL.shaderProgram
|
|
return
|
|
|
|
RSP_GBI1_MoveWord: (pc) ->
|
|
#@videoLog "RSP_GBI1_MoveWord"
|
|
switch @getGbi0MoveWordType(pc)
|
|
when consts.RSP_MOVE_WORD_MATRIX
|
|
@RSP_RDP_InsertMatrix()
|
|
when consts.RSP_MOVE_WORD_SEGMENT
|
|
dwBase = undefined
|
|
dwSegment = (@getGbi0MoveWordOffset(pc) >> 2) & 0x0F
|
|
dwBase = @getGbi0MoveWordValue(pc) & 0xFFFFFF
|
|
@segments[dwSegment] = dwBase
|
|
when consts.RSP_MOVE_WORD_NUMLIGHT
|
|
dwNumLights = (@getGbi0MoveWordValue(pc)<< 1 >>> 6)-1
|
|
@gRSP.ambientLightIndex = dwNumLights
|
|
@gRSPnumLights = dwNumLights
|
|
when consts.RSP_MOVE_WORD_LIGHTCOL
|
|
light = @getGbi0MoveWordOffset(pc) >>> 5
|
|
field = @getGbi0MoveWordOffset(pc)>>>0 & 0x7
|
|
if field is 0
|
|
if light is @gRSP.ambientLightIndex
|
|
@setAmbientLight @getGbi0MoveWordValue(pc)
|
|
else
|
|
@setLightCol light, @getGbi0MoveWordValue(pc)
|
|
when consts.RSP_MOVE_WORD_POINTS
|
|
alert "RSP_MOVE_WORD_POINTS"
|
|
return
|
|
|
|
setAmbientLight: (col) ->
|
|
@gRSP.ambientLightColor = col
|
|
r = (col >>> 24) & 0xff
|
|
g = (col >>> 16) & 0xff
|
|
b = (col >>> 8) & 0xff
|
|
a = col & 0xff
|
|
@gRSP.fAmbientLightR = r
|
|
@gRSP.fAmbientLightG = g
|
|
@gRSP.fAmbientLightB = b
|
|
@gRSP.fAmbientLightA = a
|
|
return
|
|
|
|
setLightCol: (dwLight, dwCol) ->
|
|
r = ((dwCol >>> 24) & 0xFF)
|
|
g = ((dwCol >>> 16) & 0xFF)
|
|
b = ((dwCol >>> 8) & 0xFF)
|
|
a = ((dwCol >>> 0) & 0xFF)
|
|
@gRSPlights[dwLight].r = r
|
|
@gRSPlights[dwLight].g = g
|
|
@gRSPlights[dwLight].b = b
|
|
@gRSPlights[dwLight].a = a
|
|
return
|
|
|
|
setLightDirection: (dwLight, x, y, z) ->
|
|
lightVec = new Float32Array(3)
|
|
lightVec[0] = x
|
|
lightVec[1] = y
|
|
lightVec[2] = z
|
|
lightVec = vec3.normalize(lightVec)
|
|
|
|
@gRSPlights[dwLight].x = lightVec[0]
|
|
@gRSPlights[dwLight].y = lightVec[1]
|
|
@gRSPlights[dwLight].z = lightVec[2]
|
|
return
|
|
|
|
lightVertex: (norm, v) ->
|
|
r = @gRSP.fAmbientLightR
|
|
g = @gRSP.fAmbientLightG
|
|
b = @gRSP.fAmbientLightB
|
|
#a = @gRSP.fAmbientLightA
|
|
|
|
for l in [0...@gRSPnumLights]
|
|
light = @gRSPlights[l]
|
|
fCosT = norm[0]*light.x + norm[1]*light.y + norm[2]*light.z
|
|
if fCosT > 0
|
|
r += light.r * fCosT
|
|
g += light.g * fCosT
|
|
b += light.b * fCosT
|
|
#a += light.a * fCosT
|
|
|
|
if r < 0.0
|
|
r = 0.0
|
|
if g < 0.0
|
|
g = 0.0
|
|
if b < 0.0
|
|
b = 0.0
|
|
#if a < 0.0
|
|
# a = 0.0
|
|
if r > 255.0
|
|
r = 255.0
|
|
if g > 255.0
|
|
g = 255.0
|
|
if b > 255.0
|
|
b = 255.0
|
|
#if a > 255.0
|
|
# a = 255.0
|
|
|
|
v.r = r
|
|
v.g = g
|
|
v.b = b
|
|
v.a = 255.0
|
|
return
|
|
|
|
RSP_MoveMemLight: (dwLight, dwAddr, pc) ->
|
|
if dwLight >= 16
|
|
return
|
|
|
|
@gRSPn64lights[dwLight].dwRGBA = @getGbi0MoveWordValue(dwAddr)
|
|
@gRSPn64lights[dwLight].dwRGBACopy = @getGbi0MoveWordValue(dwAddr+4)
|
|
@gRSPn64lights[dwLight].x = @getVertexLightX dwAddr
|
|
@gRSPn64lights[dwLight].y = @getVertexLightY dwAddr
|
|
@gRSPn64lights[dwLight].z = @getVertexLightZ dwAddr
|
|
|
|
# disabled in Rice's code.
|
|
# /*
|
|
# {
|
|
# // Normalize light
|
|
# double sum = (double)gRSPn64lights[dwLight].x * gRSPn64lights[dwLight].x;
|
|
# sum += (double)gRSPn64lights[dwLight].y * gRSPn64lights[dwLight].y;
|
|
# sum += (double)gRSPn64lights[dwLight].z * gRSPn64lights[dwLight].z;
|
|
# sum = sqrt(sum);
|
|
# sum = sum/128.0;
|
|
# gRSPn64lights[dwLight].x /= sum;
|
|
# gRSPn64lights[dwLight].y /= sum;
|
|
# gRSPn64lights[dwLight].z /= sum;
|
|
# }
|
|
# */
|
|
|
|
# normalize light
|
|
# sum = @gRSPn64lights[dwLight].x * @gRSPn64lights[dwLight].x
|
|
# sum += @gRSPn64lights[dwLight].y * @gRSPn64lights[dwLight].y
|
|
# sum += @gRSPn64lights[dwLight].z * @gRSPn64lights[dwLight].z
|
|
# sum = Math.sqrt(sum)
|
|
# sum = sum/128.0
|
|
# @gRSPn64lights[dwLight].x /= sum
|
|
# @gRSPn64lights[dwLight].y /= sum
|
|
# @gRSPn64lights[dwLight].z /= sum
|
|
|
|
if dwLight == @gRSP.ambientLightIndex
|
|
dwCol = @gRSPn64lights[dwLight].dwRGBA
|
|
@setAmbientLight dwCol
|
|
else
|
|
@setLightCol dwLight, @gRSPn64lights[dwLight].dwRGBA
|
|
if @getGbi0MoveWordValue(dwAddr+4) is 0 # Direction is 0! // This sucks. Give it a better name
|
|
else
|
|
@setLightDirection dwLight, @gRSPn64lights[dwLight].x, @gRSPn64lights[dwLight].y, @gRSPn64lights[dwLight].z
|
|
return
|
|
|
|
renderReset: ->
|
|
|
|
#UpdateClipRectangle();
|
|
#@resetMatrices()
|
|
@gRSP.projectionMtxTop = 0
|
|
@gRSP.modelViewMtxTop = 0
|
|
|
|
#SetZBias(0);
|
|
@gRSP.numVertices = 0
|
|
@gRSP.curTile = 0
|
|
# @gRSP.fTexScaleX = 1 / 32.0
|
|
# @gRSP.fTexScaleY = 1 / 32.0
|
|
|
|
@gl.clearDepth 1.0
|
|
@gl.depthMask true
|
|
@gl.clear @gl.DEPTH_BUFFER_BIT
|
|
return
|
|
|
|
resetMatrices: ->
|
|
@gRSP.projectionMtxTop = 0
|
|
@gRSP.modelViewMtxTop = 0
|
|
mat4.identity @gRSP.modelviewMtxs[0]
|
|
mat4.identity @gRSP.projectionMtxs[0]
|
|
|
|
i = 0
|
|
while (i < @RICE_MATRIX_STACK)
|
|
mat4.identity @gRSP.projectionMtxs[i]
|
|
mat4.identity @gRSP.modelviewMtxs[i]
|
|
i += 1
|
|
|
|
@gRSP.bMatrixIsUpdated = false
|
|
@inverseTransposeCalculated = false
|
|
return
|
|
|
|
RSP_RDP_InsertMatrix: ->
|
|
@videoLog "TODO: Insert Matrix"
|
|
@gRSP.bMatrixIsUpdated = false
|
|
return
|
|
|
|
DLParser_SetScissor: (pc) ->
|
|
@videoLog "TODO: DLParser_SetScissor"
|
|
return
|
|
|
|
RSP_GBI1_SetOtherModeH: (pc) ->
|
|
word0 = @getOtherModeH pc
|
|
length = (word0 >>> 0) & 0xFF
|
|
shift = (word0 >>> 8) & 0xFF
|
|
mask = ((1<<length)-1)<<shift
|
|
@otherModeH &= ~mask
|
|
@otherModeH |= @getOtherModeH pc+4
|
|
#alert @otherModeH
|
|
@renderStateChanged = true
|
|
return
|
|
|
|
RSP_GBI1_SetOtherModeL: (pc) ->
|
|
word0 = @getOtherModeL pc
|
|
length = (word0 >>> 0) & 0xFF
|
|
shift = (word0 >>> 8) & 0xFF
|
|
mask = ((1<<length)-1)<<shift
|
|
@otherModeL &= ~mask
|
|
@otherModeL |= @getOtherModeL pc+4
|
|
#alert dec2hex @otherModeL
|
|
@DLParser_RDPSetOtherModeL(@otherModeL)
|
|
@renderStateChanged = true
|
|
return
|
|
|
|
RSP_GBI0_Sprite2DBase: (pc) ->
|
|
@videoLog "TODO: RSP_GBI0_Sprite2DBase"
|
|
return
|
|
|
|
RSP_GBI0_Tri4: (pc) ->
|
|
@videoLog "TODO: RSP_GBI0_Tri4"
|
|
return
|
|
|
|
RSP_GBI1_RDPHalf_Cont: (pc) ->
|
|
#@videoLog "TODO: RSP_GBI1_RDPHalf_Cont"
|
|
return
|
|
|
|
RSP_GBI1_RDPHalf_2: (pc) ->
|
|
#@videoLog "TODO: RSP_GBI1_RDPHalf_2"
|
|
return
|
|
|
|
RSP_GBI1_RDPHalf_1: (pc) ->
|
|
@videoLog "TODO: RSP_GBI1_RDPHalf_1"
|
|
return
|
|
|
|
RSP_GBI1_Line3D: (pc) ->
|
|
mult = @vertexMult
|
|
v0 = @getGbi1Line3dV0(pc) * mult
|
|
v1 = @getGbi1Line3dV1(pc) * mult
|
|
v2 = @getGbi1Line3dV2(pc) * mult
|
|
v3 = @getGbi1Line3dV3(pc) * mult
|
|
#flag = @getGbi0Tri1Flag(pc)
|
|
didSucceed = @prepareTriangle v0, v1, v2
|
|
|
|
if didSucceed is false
|
|
return
|
|
|
|
#flag = @getGbi0Tri1Flag(pc)
|
|
didSucceed = @prepareTriangle v2, v3, v0
|
|
|
|
if didSucceed is false
|
|
return
|
|
|
|
pc = @dlistStack[@dlistStackPointer].pc
|
|
cmd = @getCommand(pc)
|
|
func = @currentMicrocodeMap[cmd]
|
|
if func is @RSP_GBI1_Line3D
|
|
return #loops until not tri2, then it will drawScene
|
|
|
|
if @renderStateChanged is true
|
|
@drawScene false, @activeTile
|
|
return
|
|
|
|
RSP_GBI1_ClearGeometryMode: (pc) ->
|
|
data = @getClearGeometryMode(pc)>>>0
|
|
@geometryMode &= ~data
|
|
@initGeometryMode()
|
|
@setDepthTest()
|
|
return
|
|
|
|
RSP_GBI1_SetGeometryMode: (pc) ->
|
|
data = @getSetGeometryMode(pc)>>>0
|
|
@geometryMode |= data
|
|
@initGeometryMode()
|
|
@setDepthTest()
|
|
return
|
|
|
|
initGeometryMode: () ->
|
|
# cull face
|
|
bCullFront = @geometryMode & consts.G_CULL_FRONT
|
|
bCullBack = @geometryMode & consts.G_CULL_BACK
|
|
if bCullBack isnt 0 and bCullFront isnt 0
|
|
@gl.enable @gl.CULL_FACE
|
|
@gl.cullFace @gl.FRONT_AND_BACK
|
|
else if bCullBack isnt 0
|
|
@gl.enable @gl.CULL_FACE
|
|
@gl.cullFace @gl.BACK
|
|
else if bCullFront isnt 0
|
|
@gl.enable @gl.CULL_FACE
|
|
@gl.cullFace @gl.FRONT
|
|
else
|
|
@gl.disable @gl.CULL_FACE
|
|
|
|
if (@geometryMode & consts.G_SHADE) isnt 0
|
|
@bShade = true
|
|
else
|
|
@bShade = false
|
|
#this doesn't exist in WebGL, so find a replacement if
|
|
#we need flat-shading.
|
|
#bShadeSmooth = @geometryMode & consts.G_SHADING_SMOOTH
|
|
#if bShade isnt 0 and bShadeSmooth isnt 0
|
|
# @gl.shadeModel @gl.SMOOTH
|
|
#else
|
|
# @gl.shadeModel @gl.FLAT
|
|
|
|
if (@geometryMode & consts.G_TEXTURE_GEN) isnt 0
|
|
@bTextureGen = true
|
|
else
|
|
@bTexueGen = false
|
|
if (@geometryMode & consts.G_LIGHTING) isnt 0
|
|
@bLightingEnable = true
|
|
else
|
|
@bLightingEnable = false
|
|
if (@geometryMode & consts.G_FOG) isnt 0
|
|
@bFogEnable = true
|
|
else
|
|
@bFogEnable = false
|
|
if (@geometryMode & consts.G_ZBUFFER) isnt 0
|
|
@bZBufferEnable = true
|
|
else
|
|
@bZBufferEnable = false
|
|
return
|
|
|
|
|
|
RSP_GBI1_EndDL: (pc) ->
|
|
@RDP_GFX_PopDL()
|
|
@drawScene(false, @activeTile)
|
|
#@resetState()
|
|
return
|
|
|
|
RSP_GBI1_Texture: (pc) ->
|
|
tile = @getTextureTile(pc)
|
|
@activeTile = tile
|
|
@textureTile[tile].on = @getTextureOn(pc)
|
|
@textureTile[tile].level = @getTextureLevel(pc)
|
|
@textureTile[tile].scales = @getTextureScaleS(pc) / 0x8000
|
|
@textureTile[tile].scalet = @getTextureScaleT(pc) / 0x8000
|
|
#console.log "RSP_GBI1_Texture: Tile:" + tile + " On:" + @textureTile[tile].on + " Level:" + @textureTile[tile].level + " ScaleS:" + @textureTile[tile].scales + " ScaleT:" + @textureTile[tile].scalet
|
|
@drawScene false, tile
|
|
return
|
|
|
|
popProjection: () ->
|
|
if @gRSP.projectionMtxTop > 0
|
|
@gRSP.projectionMtxTop--
|
|
return
|
|
|
|
popWorldView: () ->
|
|
if @gRSP.modelViewMtxTop > 0
|
|
@gRSP.modelViewMtxTop--
|
|
@gRSPmodelViewTop = @gRSP.modelviewMtxs[@gRSP.modelViewMtxTop]
|
|
@gRSP.bMatrixIsUpdated = true
|
|
@inverseTransposeCalculated = false
|
|
return
|
|
|
|
RSP_GBI1_PopMtx: (pc) ->
|
|
if @gbi0PopMtxIsProjection pc
|
|
@popProjection()
|
|
else
|
|
@popWorldView()
|
|
@renderStateChanged = true
|
|
return
|
|
|
|
RSP_GBI1_CullDL: (pc) ->
|
|
@videoLog "TODO: RSP_GBI1_CullDL"
|
|
return
|
|
|
|
RSP_GBI1_Tri1: (pc) ->
|
|
mult = @vertexMult
|
|
v0 = @getGbi0Tri1V0(pc) * mult
|
|
v1 = @getGbi0Tri1V1(pc) * mult
|
|
v2 = @getGbi0Tri1V2(pc) * mult
|
|
flag = @getGbi0Tri1Flag(pc)
|
|
#console.log "Tri1: "+v0+", "+v1+", "+v2+" Flag: "+flag
|
|
didSucceed = @prepareTriangle v0, v1, v2
|
|
|
|
if didSucceed is false
|
|
return
|
|
|
|
pc = @dlistStack[@dlistStackPointer].pc
|
|
cmd = @getCommand(pc)
|
|
func = @currentMicrocodeMap[cmd]
|
|
if func is @RSP_GBI1_Tri1
|
|
return #loops until not tri1, then it will drawScene
|
|
|
|
if @renderStateChanged is true
|
|
@drawScene false, @activeTile
|
|
return
|
|
|
|
RSP_GBI1_Noop: (pc) ->
|
|
#@videoLog "TODO: RSP_GBI1_Noop"
|
|
return
|
|
|
|
RDP_TriFill: (pc) ->
|
|
@videoLog "TODO: RDP_TriFill"
|
|
return
|
|
|
|
RDP_TriFillZ: (pc) ->
|
|
@videoLog "RDP_TriFillZ"
|
|
return
|
|
|
|
RDP_TriTxtr: (pc) ->
|
|
@videoLog "TODO: RDP_TriTxtr"
|
|
return
|
|
|
|
RDP_TriTxtrZ: (pc) ->
|
|
@videoLog "TODO: RDP_TriTxtrZ"
|
|
return
|
|
|
|
RDP_TriShade: (pc) ->
|
|
@videoLog "TODO: RDP_TriShade"
|
|
return
|
|
|
|
RDP_TriShadeZ: (pc) ->
|
|
@videoLog "TODO: RDP_TriShadeZ"
|
|
return
|
|
|
|
RDP_TriShadeTxtr: (pc) ->
|
|
@videoLog "TODO: RDP_TriShadeTxtr"
|
|
return
|
|
|
|
RDP_TriShadeTxtrZ: (pc) ->
|
|
@videoLog "TODO: RDP_TriShadeTxtrZ"
|
|
return
|
|
|
|
DLParser_TexRect: (pc, isFillRect) ->
|
|
depthTestEnabled = true
|
|
if depthTestEnabled
|
|
#@setDepthTest()
|
|
@gl.enable @gl.DEPTH_TEST
|
|
@gl.depthFunc @gl.LEQUAL
|
|
else
|
|
@gl.disable @gl.DEPTH_TEST
|
|
|
|
xh = @getTexRectXh(pc) >>> 2
|
|
yh = @getTexRectYh(pc) >>> 2
|
|
tileno = @getTexRectTileNo(pc)
|
|
xl = @getTexRectXl(pc) >>> 2
|
|
yl = @getTexRectYl(pc) >>> 2
|
|
s = @getTexRectS(pc) >>> 5
|
|
t = @getTexRectT(pc) >>> 5
|
|
dsdx = @getTexRectDsDx(pc) >>> 10
|
|
dtdy = @getTexRectDtDy(pc) >>> 10
|
|
|
|
if @cycleType is consts.CYCLE_TYPE_COPY
|
|
dsdx *= 0.25
|
|
|
|
if @cycleType is consts.CYCLE_TYPE_FILL or @cycleType is consts.CYCLE_TYPE_COPY
|
|
xh += 1.0
|
|
yh += 1.0
|
|
|
|
#console.log "Texrect: UL("+xl+","+yl+") LR("+xh+","+yh+") Tile:"+tileno+" TexCoord:("+s+","+t+") TexSlope:("+dsdx+","+dtdy+")"
|
|
@renderer.texRect tileno, xl, yl, xh, yh, s, t, dsdx, dtdy, @textureTile[tileno], @tmem, this, isFillRect
|
|
@hasTexture = true
|
|
#@setDepthTest()
|
|
#@drawScene false, 7
|
|
return
|
|
|
|
DLParser_TexRectFlip: (pc) ->
|
|
@videoLog "TODO: DLParser_TexRectFlip"
|
|
return
|
|
|
|
DLParser_RDPLoadSynch: (pc) ->
|
|
@renderStateChanged = true
|
|
#@videoLog "TODO: DLParser_RDPLoadSynch"
|
|
return
|
|
|
|
DLParser_RDPPipeSynch: (pc) ->
|
|
#@videoLog "TODO: DLParser_RDPPipeSynch"
|
|
return
|
|
|
|
DLParser_RDPTileSynch: (pc) ->
|
|
#@videoLog "TODO: DLParser_RDPTileSynch"
|
|
return
|
|
|
|
DLParser_RDPFullSynch: (pc) ->
|
|
#@drawScene(7, false)
|
|
return
|
|
|
|
DLParser_SetKeyGB: (pc) ->
|
|
@videoLog "TODO: DLParser_SetKeyGB"
|
|
return
|
|
|
|
DLParser_SetKeyR: (pc) ->
|
|
@videoLog "TODO: DLParser_SetKeyR"
|
|
return
|
|
|
|
DLParser_SetConvert: (pc) ->
|
|
@videoLog "TODO: DLParser_SetConvert"
|
|
return
|
|
|
|
DLParser_SetPrimDepth: (pc) ->
|
|
@videoLog "TODO: DLParser_SetPrimDepth"
|
|
return
|
|
|
|
DLParser_RDPSetOtherModeL: (otherModeL) ->
|
|
if (otherModeL & (consts.RDP_ALPHA_COMPARE_THRESHOLD|consts.RDP_ALPHA_COMPARE_DITHER)) isnt 0
|
|
@alphaTestEnabled = 1
|
|
else
|
|
@alphaTestEnabled = 0
|
|
return
|
|
|
|
DLParser_LoadTLut: (pc) ->
|
|
tile = @getSetTileSizeTile(pc)
|
|
uls = @textureTile[tile].uls = @getSetTileSizeUls(pc)
|
|
ult = @textureTile[tile].ult = @getSetTileSizeUlt(pc)
|
|
lrs = @textureTile[tile].lrs = @getSetTileSizeLrs(pc)
|
|
lrt = @textureTile[tile].lrt = @getSetTileSizeLrt(pc)
|
|
|
|
ramOffset = @texImg.addr + (ult>>>2) * ((@texImg.width << consts.TXT_SIZE_16b)>>>1) + (((uls>>>2)<<consts.TXT_SIZE_16b)>>>1)
|
|
bytes = (((lrs - uls)>>>2)+1)<<1
|
|
tmemOffset = @textureTile[tile].tmem<<3
|
|
|
|
`const tlut = this.tlut`
|
|
`const ram = this.core.memory.u8`
|
|
for i in [0...bytes]
|
|
tlut[tmemOffset+i] = ram[ramOffset+i]
|
|
return
|
|
|
|
DLParser_SetTileSize: (pc) ->
|
|
tile = @getSetTileSizeTile(pc)
|
|
@textureTile[tile].uls = @getSetTileSizeUls(pc)
|
|
@textureTile[tile].ult = @getSetTileSizeUlt(pc)
|
|
@textureTile[tile].lrs = @getSetTileSizeLrs(pc)
|
|
@textureTile[tile].lrt = @getSetTileSizeLrt(pc)
|
|
#console.log "SetTileSize: UL("+@textureTile[tile].uls+"/"+@textureTile[tile].ult+") LR("+@textureTile[tile].lrs+"/"+@textureTile[tile].lrt+") Dim: "+@textureTile[tile].width+"x"+@textureTile[tile].height
|
|
return
|
|
|
|
DLParser_LoadBlock: (pc) ->
|
|
tile = @getLoadBlockTile(pc)
|
|
uls = @getLoadBlockUls(pc)
|
|
ult = @getLoadBlockUlt(pc)
|
|
lrs = @getLoadBlockLrs(pc)
|
|
dxt = @getLoadBlockDxt(pc)
|
|
#console.log "LoadBlock: Tile:"+tile+" UL("+uls+"/"+ult+") LRS:"+lrs+" DXT: 0x"+dec2hex(dxt)
|
|
#textureAddr = @core.memory.u8[@texImg.addr])
|
|
bytesToXfer = (lrs+1) * @textureTile[tile].siz
|
|
if bytesToXfer > 4096
|
|
console.error "LoadBlock is making too large of a transfer. "+bytesToXfer+" bytes"
|
|
i=0
|
|
`const u8 = this.core.memory.u8
|
|
var addr = this.texImg.addr|0
|
|
const tmem = this.tmem`
|
|
while i < bytesToXfer
|
|
tmem[i] = u8[addr]
|
|
i++
|
|
addr++
|
|
return
|
|
|
|
DLParser_LoadTile: (pc) ->
|
|
tile = @getLoadBlockTile(pc)
|
|
lrs = @textureTile[tile].lrs
|
|
#console.log "LoadBlock: Tile:"+tile+" UL("+uls+"/"+ult+") LRS:"+lrs+" DXT: 0x"+dec2hex(dxt)
|
|
#textureAddr = @core.memory.u8[@texImg.addr])
|
|
bytesToXfer = (lrs+1) * @textureTile[tile].siz
|
|
bytesToXfer = 4096
|
|
if bytesToXfer > 4096
|
|
console.error "LoadTile is making too large of a transfer. "+bytesToXfer+" bytes"
|
|
i=0
|
|
|
|
if typeof @texImg.addr isnt 'undefined'
|
|
`const u8 = this.core.memory.u8
|
|
var addr = this.texImg.addr|0
|
|
const tmem = this.tmem`
|
|
while i < bytesToXfer
|
|
tmem[i] = u8[addr]
|
|
i++
|
|
addr++
|
|
return
|
|
|
|
DLParser_SetTile: (pc) ->
|
|
tile = @getSetTileTile(pc)
|
|
@textureTile[tile].fmt = @getSetTileFmt(pc)
|
|
@textureTile[tile].siz = @getSetTileSiz(pc)
|
|
@textureTile[tile].line = @getSetTileLine(pc)
|
|
@textureTile[tile].tmem = @getSetTileTmem(pc)
|
|
@textureTile[tile].pal = @getSetTilePal(pc)
|
|
@textureTile[tile].cmt = @getSetTileCmt(pc)
|
|
@textureTile[tile].cms = @getSetTileCms(pc)
|
|
@textureTile[tile].mirrorS = @getSetTileMirrorS(pc)
|
|
@textureTile[tile].mirrorT = @getSetTileMirrorT(pc)
|
|
@textureTile[tile].maskt = @getSetTileMaskt(pc)
|
|
@textureTile[tile].masks = @getSetTileMasks(pc)
|
|
@textureTile[tile].shiftt = @getSetTileShiftt(pc)
|
|
@textureTile[tile].shifts = @getSetTileShifts(pc)
|
|
@textureTile[tile].otherModeL = @otherModeL
|
|
|
|
#if @combineD0 == 4
|
|
#console.log "SetTile:"+tile+" FMT:"+@textureTile[tile].fmt+" SIZ:"+@textureTile[tile].siz+" LINE: "+@textureTile[tile].line+" TMEM:"+@textureTile[tile].tmem+" PAL:"+@textureTile[tile].pal+" CMS/T:"+@textureTile[tile].cms+"/"+@textureTile[tile].cmt+" MASKS/T:"+@textureTile[tile].masks+"/"+@textureTile[tile].maskt+" SHIFTS/T:"+@textureTile[tile].shifts+"/"+@textureTile[tile].shiftt
|
|
return
|
|
|
|
DLParser_FillRect: (pc) ->
|
|
# if @zDepthImage.addr isnt undefined and (@zDepthImage.addr is @zColorImage.addr)
|
|
# @gl.clearDepth 1.0
|
|
# @gl.depthMask true
|
|
# @gl.clear @gl.DEPTH_BUFFER_BIT
|
|
#@gl.clearColor @fillColor[0], @fillColor[1], @fillColor[2], 1.0
|
|
#@gl.clear @gl.COLOR_BUFFER_BIT
|
|
#@gl.clearColor 0.0, 0.0, 0.0, 0.0
|
|
#return
|
|
|
|
@DLParser_TexRect pc, true
|
|
|
|
# if @fillColor isnt undefined
|
|
# if @zDepthImage.addr isnt @zColorImage.addr
|
|
# @gl.clearColor 1.0, @fillColor[1], @fillColor[2], 1.0
|
|
# @gl.clear @gl.COLOR_BUFFER_BIT
|
|
return
|
|
|
|
DLParser_SetFillColor: (pc) ->
|
|
@fillColor = []
|
|
@fillColor.push @getSetFillColorR(pc)/255.0
|
|
@fillColor.push @getSetFillColorG(pc)/255.0
|
|
@fillColor.push @getSetFillColorB(pc)/255.0
|
|
@fillColor.push @getSetFillColorA(pc)/255.0
|
|
@gl.uniform4fv @core.webGL.shaderProgram.uFillColor, @fillColor
|
|
return
|
|
|
|
DLParser_SetFogColor: (pc) ->
|
|
@videoLog "TODO: DLParser_SetFogColor"
|
|
return
|
|
|
|
DLParser_SetBlendColor: (pc) ->
|
|
@blendColor = []
|
|
@blendColor.push @getSetFillColorR(pc)/255.0
|
|
@blendColor.push @getSetFillColorG(pc)/255.0
|
|
@blendColor.push @getSetFillColorB(pc)/255.0
|
|
@blendColor.push @getSetFillColorA(pc)/255.0
|
|
@gl.uniform4fv @core.webGL.shaderProgram.uBlendColor, @blendColor
|
|
return
|
|
|
|
DLParser_SetPrimColor: (pc) ->
|
|
@primColor = []
|
|
@primColor.push @getSetPrimColorR(pc)/255.0
|
|
@primColor.push @getSetPrimColorG(pc)/255.0
|
|
@primColor.push @getSetPrimColorB(pc)/255.0
|
|
@primColor.push @getSetPrimColorA(pc)/255.0
|
|
#alert @primColor
|
|
@gl.uniform4fv @core.webGL.shaderProgram.uPrimColor, @primColor
|
|
return
|
|
|
|
DLParser_SetEnvColor: (pc) ->
|
|
@envColor = []
|
|
@envColor.push @getSetEnvColorR(pc)/255.0
|
|
@envColor.push @getSetEnvColorG(pc)/255.0
|
|
@envColor.push @getSetEnvColorB(pc)/255.0
|
|
@envColor.push @getSetEnvColorA(pc)/255.0
|
|
@gl.uniform4fv @core.webGL.shaderProgram.uEnvColor, @envColor
|
|
return
|
|
|
|
prepareTriangle: (dwV0, dwV1, dwV2) ->
|
|
#SP_Timing(SP_Each_Triangle);
|
|
didSucceed = undefined #(CRender::g_pRender->IsTextureEnabled() || this.gRSP.ucode == 6 );
|
|
textureFlag = false
|
|
didSucceed = @initVertex(dwV0, @gRSP.numVertices, textureFlag)
|
|
didSucceed = @initVertex(dwV1, @gRSP.numVertices + 1, textureFlag) if didSucceed
|
|
didSucceed = @initVertex(dwV2, @gRSP.numVertices + 2, textureFlag) if didSucceed
|
|
@gRSP.numVertices += 3 if didSucceed
|
|
didSucceed
|
|
|
|
initVertex: (dwV, vtxIndex, bTexture) ->
|
|
#console.log "Vertex Index: "+vtxIndex+" dwV:"+dwV
|
|
return false if dwV >= consts.MAX_VERTS
|
|
|
|
offset = 4 * @triangleVertexPositionBuffer.numItems++ # postfix addition is intentional for performance
|
|
vertex = @N64VertexList[dwV]
|
|
|
|
@triVertices[offset] = vertex.x
|
|
@triVertices[offset+1] = vertex.y
|
|
@triVertices[offset+2] = vertex.z
|
|
@triVertices[offset+3] = vertex.w * this.vertexMult
|
|
@triVertices[offset+3] = 1.0 if vertex.w is 0
|
|
|
|
colorOffset = @triangleVertexColorBuffer.numItems++ << 2 # postfix addition is intentional for performance
|
|
@triColorVertices[colorOffset] = vertex.r
|
|
@triColorVertices[colorOffset + 1] = vertex.g
|
|
@triColorVertices[colorOffset + 2] = vertex.b
|
|
@triColorVertices[colorOffset + 3] = vertex.a
|
|
|
|
texOffset = @triangleVertexTextureCoordBuffer.numItems++ << 1 # postfix addition is intentional for performance
|
|
@triTextureCoords[texOffset] = vertex.u
|
|
@triTextureCoords[texOffset + 1] = vertex.v
|
|
true
|
|
|
|
setBlendFunc: () ->
|
|
`const CYCLE_TYPE_1 = 0`
|
|
`const CYCLE_TYPE_2 = 1`
|
|
`const CYCLE_TYPE_COPY = 2`
|
|
`const CYCLE_TYPE_FILL = 3`
|
|
`const CVG_DST_CLAMP = 0`
|
|
`const CVG_DST_WRAP = 0x100`
|
|
`const CVG_DST_FULL = 0x200`
|
|
`const CVG_DST_SAVE = 0x300`
|
|
`const BLEND_NOOP = 0x0000`
|
|
`const BLEND_NOOP5 = 0xcc48`
|
|
`const BLEND_NOOP4 = 0xcc08`
|
|
`const BLEND_FOG_ASHADE = 0xc800`
|
|
`const BLEND_FOG_3 = 0xc000`
|
|
`const BLEND_FOG_MEM = 0xc440`
|
|
`const BLEND_FOG_APRIM = 0xc400`
|
|
`const BLEND_BLENDCOLOR = 0x8c88`
|
|
`const BLEND_BI_AFOG = 0x8400`
|
|
`const BLEND_BI_AIN = 0x8040`
|
|
`const BLEND_MEM = 0x4c40`
|
|
`const BLEND_FOG_MEM_3 = 0x44c0`
|
|
`const BLEND_NOOP3 = 0x0c48`
|
|
`const BLEND_PASS = 0x0c08`
|
|
`const BLEND_FOG_MEM_IN_MEM = 0x0440`
|
|
`const BLEND_FOG_MEM_FOG_MEM = 0x04c0`
|
|
`const BLEND_OPA = 0x0044`
|
|
`const BLEND_XLU = 0x0040`
|
|
`const BLEND_MEM_ALPHA_IN = 0x4044`
|
|
|
|
blendMode1 = @otherModeL >>> 16 & 0xCCCC
|
|
blendMode2 = @otherModeL >>> 16 & 0x3333
|
|
@cycleType = @otherModeH >> 20 & 0x3
|
|
|
|
switch @cycleType
|
|
when CYCLE_TYPE_FILL
|
|
@gl.disable @gl.BLEND
|
|
when CYCLE_TYPE_COPY
|
|
#this is wrong, but better for now. Hud has no alpha.
|
|
# We should be calculating alpha transparency at the bottom of this function
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
when CYCLE_TYPE_2
|
|
forceBl = @otherModeL >> 14 & 0x1
|
|
zCmp = @otherModeL >> 4 & 0x1
|
|
alphaCvgSel = @otherModeL >> 13 & 0x1
|
|
cvgXAlpha = @otherModeL >> 12 & 0x1
|
|
|
|
if forceBl is 1 and zCmp is 1
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
# else if alphaCvgSel is 1 && cvgXAlpha is 0
|
|
# @gl.blendFunc @gl.ONE, @gl.ZERO
|
|
# @gl.enable @gl.BLEND
|
|
else switch blendMode1+blendMode2
|
|
when (BLEND_PASS+(BLEND_PASS>>2)), (BLEND_FOG_APRIM+(BLEND_PASS>>2))
|
|
@gl.blendFunc @gl.ONE, @gl.ZERO
|
|
@gl.enable @gl.blendFunc
|
|
if @cvgXAlpha is 1
|
|
@gl.blendFunc @gl.ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
# if( gRDP.otherMode.alpha_cvg_sel )
|
|
# {
|
|
# Enable();
|
|
# }
|
|
# else
|
|
# {
|
|
# Enable();
|
|
# }
|
|
# break;
|
|
when BLEND_PASS+(BLEND_OPA>>2)
|
|
if cvgXAlpha is 1 and alphaCvgSel is 1
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
else
|
|
@gl.blendFunc @gl.ONE, @gl.ZERO
|
|
@gl.enable @gl.BLEND
|
|
when (BLEND_PASS + (BLEND_XLU>>2)), (BLEND_FOG_ASHADE + (BLEND_XLU>>2)), (BLEND_FOG_APRIM + (BLEND_XLU>>2)), (BLEND_FOG_MEM_FOG_MEM + (BLEND_PASS>>2)), (BLEND_XLU + (BLEND_XLU>>2)), (BLEND_BI_AFOG + (BLEND_XLU>>2)), (BLEND_XLU + (BLEND_FOG_MEM_IN_MEM>>2)), (BLEND_PASS + (BLEND_FOG_MEM_IN_MEM>>2))
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
when BLEND_FOG_MEM_FOG_MEM + (BLEND_OPA>>2)
|
|
if @fogIsImplemented
|
|
@gl.blendFunc @gl.ONE, @gl.ZERO
|
|
@gl.enable @gl.BLEND
|
|
else
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
|
|
when (BLEND_FOG_APRIM + (BLEND_OPA>>2)), (BLEND_FOG_ASHADE + (BLEND_OPA>>2)), (BLEND_BI_AFOG + (BLEND_OPA>>2)), (BLEND_FOG_ASHADE + (BLEND_NOOP>>2)), (BLEND_NOOP + (BLEND_OPA>>2)), (BLEND_NOOP4 + (BLEND_NOOP>>2)), (BLEND_FOG_ASHADE+(BLEND_PASS>>2)), (BLEND_FOG_3+(BLEND_PASS>>2))
|
|
if @fogIsImplemented
|
|
@gl.blendFunc @gl.ONE, @gl.ZERO
|
|
@gl.enable @gl.BLEND
|
|
else
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
|
|
when BLEND_FOG_ASHADE+0x0301
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ZERO
|
|
@gl.enable @gl.BLEND
|
|
when 0x0c08+0x1111
|
|
@gl.blendFunc @gl.ZERO, @gl.DEST_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
else
|
|
if blendMode2 == BLEND_PASS>>2
|
|
@gl.blendFunc @gl.ONE, @g.ZERO
|
|
else
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
else # 1/2 Cycle or Copy
|
|
forceBl = @otherModeL >> 14 & 0x1
|
|
zCmp = @otherModeL >> 4 & 0x1
|
|
if forceBl is 1 and zCmp is 1 and blendMode1 isnt BLEND_FOG_ASHADE
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
# if( gRDP.otherMode.force_bl && options.enableHackForGames == HACK_FOR_COMMANDCONQUER )
|
|
# {
|
|
# BlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
|
|
# Enable();
|
|
# break;
|
|
# }
|
|
else switch blendMode1
|
|
# //switch ( blendmode_2<<2 )
|
|
when BLEND_XLU, BLEND_BI_AIN, BLEND_FOG_MEM, BLEND_FOG_MEM_IN_MEM, BLEND_BLENDCOLOR, 0x00c0
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
when BLEND_MEM_ALPHA_IN
|
|
@gl.blendFunc @gl.ZERO, @gl.DEST_ALPHA
|
|
@gl.enable @gl.BLEND
|
|
when BLEND_PASS
|
|
alphaCvgSel = @otherModeL >> 13 & 0x1
|
|
@gl.blendFunc @gl.ONE, @gl.ZERO
|
|
if alphaCvgSel != 0
|
|
@gl.enable @gl.BLEND
|
|
else
|
|
@gl.disable @gl.BLEND
|
|
when BLEND_OPA
|
|
HACK_FOR_MARIO_TENNIS = true
|
|
if HACK_FOR_MARIO_TENNIS
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
else
|
|
@gl.blendFunc @gl.ONE, @gl.ZERO
|
|
@gl.enable @gl.BLEND
|
|
when BLEND_NOOP, BLEND_FOG_ASHADE, BLEND_FOG_MEM_3, BLEND_BI_AFOG
|
|
@gl.blendFunc @gl.ONE, @gl.ZERO
|
|
@gl.enable @gl.BLEND
|
|
when BLEND_FOG_APRIM
|
|
@gl.blendFunc @gl.ONE_MINUS_SRC_ALPHA, @gl.ZERO
|
|
@gl.enable @gl.BLEND
|
|
when BLEND_NOOP3, BLEND_NOOP5
|
|
@gl.blendFunc @gl.ZERO, @gl.ONE
|
|
@gl.enable @gl.BLEND
|
|
when BLEND_MEM
|
|
# WaveRace
|
|
@gl.blendFunc @gl.ZERO, @gl.ONE
|
|
@gl.blendEquation @gl.FUNC_ADD
|
|
@gl.enable @gl.BLEND
|
|
else
|
|
@gl.blendFunc @gl.SRC_ALPHA, @gl.ONE_MINUS_SRC_ALPHA
|
|
@gl.blendEquation @gl.FUNC_ADD
|
|
@gl.enable @gl.BLEND
|
|
#render->SetAlphaTestEnable(TRUE);
|
|
return
|
|
|
|
setDepthTest: () ->
|
|
zBufferMode = (@geometryMode & consts.G_ZBUFFER) isnt 0
|
|
zCmp = (@otherModeL & consts.Z_COMPARE) isnt 0
|
|
zUpd = (@otherModeL & consts.Z_UPDATE) isnt 0
|
|
if ((zBufferMode and zCmp) or zUpd)
|
|
@gl.enable @gl.DEPTH_TEST
|
|
# @gl.depthFunc @gl.LEQUAL
|
|
# @gl.depthRange 0, 0.0001 # fixes shadows
|
|
# @gl.depthMask true
|
|
else
|
|
@gl.disable @gl.DEPTH_TEST
|
|
@gl.depthMask zUpd
|
|
return
|
|
|
|
drawScene: (useTexture, tileno) ->
|
|
@setBlendFunc()
|
|
@setDepthTest()
|
|
|
|
@renderStateChanged = false
|
|
|
|
if @triangleVertexPositionBuffer.numItems > 0
|
|
@gl.bindBuffer @gl.ARRAY_BUFFER, @triangleVertexPositionBuffer
|
|
@gl.bufferData @gl.ARRAY_BUFFER, @triVertices.subarray(0, @triangleVertexPositionBuffer.numItems*@triangleVertexPositionBuffer.itemSize), @gl.STATIC_DRAW
|
|
@gl.enableVertexAttribArray @core.webGL.shaderProgram.vertexPositionAttribute
|
|
@gl.vertexAttribPointer @core.webGL.shaderProgram.vertexPositionAttribute, @triangleVertexPositionBuffer.itemSize, @gl.FLOAT, false, 0, 0
|
|
|
|
if @triangleVertexColorBuffer.numItems > 0
|
|
@gl.bindBuffer @gl.ARRAY_BUFFER, @triangleVertexColorBuffer
|
|
@gl.bufferData @gl.ARRAY_BUFFER, @triColorVertices.subarray(0, @triangleVertexColorBuffer.numItems*@triangleVertexColorBuffer.itemSize), @gl.STATIC_DRAW
|
|
@gl.enableVertexAttribArray @core.webGL.shaderProgram.vertexColorAttribute
|
|
@gl.vertexAttribPointer @core.webGL.shaderProgram.vertexColorAttribute, @triangleVertexColorBuffer.itemSize, @gl.UNSIGNED_BYTE, true, 0, 0
|
|
|
|
if @triangleVertexTextureCoordBuffer.numItems > 0
|
|
@gl.bindBuffer @gl.ARRAY_BUFFER, @triangleVertexTextureCoordBuffer
|
|
@gl.bufferData @gl.ARRAY_BUFFER, @triTextureCoords.subarray(0, @triangleVertexTextureCoordBuffer.numItems*@triangleVertexTextureCoordBuffer.itemSize), @gl.STATIC_DRAW
|
|
@gl.enableVertexAttribArray @core.webGL.shaderProgram.textureCoordAttribute
|
|
@gl.vertexAttribPointer @core.webGL.shaderProgram.textureCoordAttribute, @triangleVertexTextureCoordBuffer.itemSize, @gl.FLOAT, false, 0, 0
|
|
tile = @textureTile[tileno]
|
|
tileWidth = ((tile.lrs >> 2) + 1) - tile.uls
|
|
tileHeight = ((tile.lrt >> 2) + 1) - tile.ult
|
|
tData = undefined
|
|
if tileWidth > 0 and tileHeight > 0
|
|
tData = @renderer.formatTexture(tile, @tmem, this)
|
|
if tData isnt undefined and tData.textureData isnt undefined
|
|
textureData = tData.textureData
|
|
@gl.activeTexture(@gl.TEXTURE0 + tileno)
|
|
@gl.bindTexture(@gl.TEXTURE_2D, @colorsTexture0)
|
|
wrapS = @gl.REPEAT
|
|
wrapT = @gl.REPEAT
|
|
if ((tile.cms is consts.RDP_TXT_CLAMP) or (tile.masks is 0))
|
|
wrapS = @gl.CLAMP_TO_EDGE
|
|
else if tile.cms is consts.RDP_TXT_MIRROR
|
|
wrapS = @gl.MIRRORED_REPEAT
|
|
if ((tile.cmt is consts.RDP_TXT_CLAMP) or (tile.maskt is 0))
|
|
wrapT = @gl.CLAMP_TO_EDGE
|
|
else if tile.cmt is consts.RDP_TXT_MIRROR
|
|
wrapT = @gl.MIRRORED_REPEAT
|
|
@gl.texParameterf(@gl.TEXTURE_2D, @gl.TEXTURE_WRAP_S, wrapS)
|
|
@gl.texParameterf(@gl.TEXTURE_2D, @gl.TEXTURE_WRAP_T, wrapT)
|
|
@gl.texParameterf(@gl.TEXTURE_2D, @gl.TEXTURE_MAG_FILTER, @gl.LINEAR)
|
|
@gl.texParameterf(@gl.TEXTURE_2D, @gl.TEXTURE_MIN_FILTER, @gl.NEAREST)
|
|
@gl.texImage2D(@gl.TEXTURE_2D, 0, @gl.RGBA, tileWidth, tileHeight, 0, @gl.RGBA, @gl.UNSIGNED_BYTE, textureData)
|
|
|
|
# if @primColor.length > 0
|
|
# @gl.uniform4fv @core.webGL.shaderProgram.uPrimColor, @primColor
|
|
|
|
# if @fillColor.length > 0
|
|
# @gl.uniform4fv @core.webGL.shaderProgram.uFillColor, @fillColor
|
|
|
|
# if @blendColor.length > 0
|
|
# @gl.uniform4fv @core.webGL.shaderProgram.uBlendColor, @blendColor
|
|
|
|
# if @envColor.length > 0
|
|
# @gl.uniform4fv @core.webGL.shaderProgram.uEnvColor, @envColor
|
|
|
|
# if isFillRect is true
|
|
# @cycleType = 3
|
|
|
|
#@gl.uniform1i @core.webGL.shaderProgram.otherModeL, @otherModeL
|
|
#@gl.uniform1i @core.webGL.shaderProgram.otherModeH, @otherModeH
|
|
@gl.uniform1i @core.webGL.shaderProgram.cycleType, @cycleType
|
|
@gl.uniform1i @core.webGL.shaderProgram.uAlphaTestEnabled, @alphaTestEnabled
|
|
|
|
# Matrix Uniforms
|
|
@gl.uniformMatrix4fv(@core.webGL.shaderProgram.pMatrixUniform, false, @gRSP.projectionMtxs[@gRSP.projectionMtxTop]);
|
|
@gl.uniformMatrix4fv(@core.webGL.shaderProgram.mvMatrixUniform, false, @gRSP.modelviewMtxs[@gRSP.modelViewMtxTop]);
|
|
|
|
if @triangleVertexPositionBuffer.numItems > 0
|
|
if @core.settings.wireframe is true
|
|
@gl.drawArrays @gl.LINES, 0, @triangleVertexPositionBuffer.numItems
|
|
else
|
|
@gl.drawArrays @gl.TRIANGLES, 0, @triangleVertexPositionBuffer.numItems
|
|
|
|
@triangleVertexPositionBuffer.numItems = 0
|
|
@triangleVertexColorBuffer.numItems = 0
|
|
@triangleVertexTextureCoordBuffer.numItems = 0
|
|
@gRSP.numVertices = 0
|
|
return
|
|
|
|
resetState: ->
|
|
@geometryMode = 0
|
|
@initGeometryMode()
|
|
@alphaTestEnabled = 0
|
|
@activeTile = 0
|
|
return
|
|
|
|
initBuffers: ->
|
|
@triangleVertexPositionBuffer = @gl.createBuffer()
|
|
@gl.bindBuffer @gl.ARRAY_BUFFER, @triangleVertexPositionBuffer
|
|
@triangleVertexPositionBuffer.itemSize = 4
|
|
@triangleVertexPositionBuffer.numItems = 0
|
|
|
|
@triangleVertexColorBuffer = @gl.createBuffer()
|
|
@gl.bindBuffer @gl.ARRAY_BUFFER, @triangleVertexColorBuffer
|
|
@triangleVertexColorBuffer.itemSize = 4
|
|
@triangleVertexColorBuffer.numItems = 0
|
|
|
|
@triangleVertexTextureCoordBuffer = @gl.createBuffer()
|
|
@gl.bindBuffer @gl.ARRAY_BUFFER, @triangleVertexTextureCoordBuffer
|
|
@triangleVertexTextureCoordBuffer.itemSize = 2
|
|
@triangleVertexTextureCoordBuffer.numItems = 0
|
|
return
|
|
|
|
#hack global space until we export classes properly
|
|
#node.js uses exports; browser uses this (window)
|
|
root = exports ? self
|
|
root.C1964jsVideoHLE = C1964jsVideoHLE
|