Initial Commit
This commit is contained in:
BIN
icon/rcbasic.ico
Normal file
BIN
icon/rcbasic.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 264 KiB |
BIN
icon/rcbasic1.ico
Normal file
BIN
icon/rcbasic1.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
BIN
icon/rcbasic2.ico
Normal file
BIN
icon/rcbasic2.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
45
rcbasic_build/cbc_spec.txt
Normal file
45
rcbasic_build/cbc_spec.txt
Normal file
@@ -0,0 +1,45 @@
|
||||
CBC VERSION 4 SPECIFICATION
|
||||
--------------------------------
|
||||
|
||||
FIELD SIZE
|
||||
-----------------------------------
|
||||
RC4[XX] 5 bytes
|
||||
|
||||
|
||||
//----TYPE HEADER-----
|
||||
UTYPE_COUNT 8 bytes
|
||||
|
||||
//----EACH TYPE------
|
||||
FIELD_COUNT 8 BYTES
|
||||
|
||||
//----EACH FIELD----
|
||||
FIELD_TYPE 8 BYTES
|
||||
* NUMBER = 0
|
||||
* STRING = 1
|
||||
* USER = 2
|
||||
FIELD_UTYPE 8 BYTES
|
||||
FIELD_DIMENSIONS 8 BYTES
|
||||
|
||||
|
||||
//----PROGRAM HEADER-----
|
||||
N REGISTER COUNT 8 BYTES
|
||||
S REGISTER COUNT 8 BYTES
|
||||
U REGISTER COUNT 8 BYTES
|
||||
|
||||
N STACK SIZE 8 BYTES
|
||||
S STACK SIZE 8 BYTES
|
||||
U STACK SIZE 8 BYTES
|
||||
|
||||
LOOP STACK SIZE 8 BYTES
|
||||
|
||||
NUM ID COUNT 8 BYTES
|
||||
STRING ID COUNT 8 BYTES
|
||||
USER ID COUNT 8 BYTES
|
||||
|
||||
CODE SEGMENT SIZE 8 BYTES
|
||||
DATA SEGMENT SIZE 8 BYTES
|
||||
|
||||
|
||||
//----PROGRAM----
|
||||
CODE SEGMENT CODE SEGMENT SIZE
|
||||
DATA SEGMENT DATA SEGMENT SIZE
|
||||
35
rcbasic_build/constants.h
Normal file
35
rcbasic_build/constants.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef CONSTANTS_H_INCLUDED
|
||||
#define CONSTANTS_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct rc_user_constant
|
||||
{
|
||||
string const_name;
|
||||
vector<string> const_tokens;
|
||||
};
|
||||
|
||||
vector<rc_user_constant> rc_constants;
|
||||
|
||||
int create_constant(string c_name)
|
||||
{
|
||||
for(int i = 0; i < rc_constants.size(); i++)
|
||||
{
|
||||
if(rc_constants[i].const_name.compare(c_name)==0)
|
||||
return -1; //constant already exists
|
||||
}
|
||||
int const_id = rc_constants.size();
|
||||
|
||||
rc_user_constant c;
|
||||
c.const_name = c_name;
|
||||
|
||||
rc_constants.push_back(c);
|
||||
return const_id;
|
||||
}
|
||||
|
||||
void add_const_token(int c_id, string c_token)
|
||||
{
|
||||
rc_constants[c_id].const_tokens.push_back(c_token);
|
||||
}
|
||||
|
||||
#endif // CONSTANTS_H_INCLUDED
|
||||
516
rcbasic_build/embedded_functions.bas
Normal file
516
rcbasic_build/embedded_functions.bas
Normal file
@@ -0,0 +1,516 @@
|
||||
'StringFill
|
||||
'Stack_Size_N
|
||||
'Stack_Size_S
|
||||
'Text I/O
|
||||
sub FPrint(txt$)
|
||||
function Input$(prompt$)
|
||||
'Arrays
|
||||
function ArrayDim(Byref id)
|
||||
function StringArrayDim(Byref id$)
|
||||
function NumberArrayDim(Byref id)
|
||||
function ArraySize(Byref id, array_dim)
|
||||
function StringArraySize(Byref id$, array_dim)
|
||||
function NumberArraySize(Byref id, array_dim)
|
||||
'Math
|
||||
function Abs(n)
|
||||
function ACos(n)
|
||||
function AndBit(a,b)
|
||||
function ASin(n)
|
||||
function ATan(n)
|
||||
function Bin$(n)
|
||||
function CInt32(i)
|
||||
function CInt64(i)
|
||||
function Cos(n)
|
||||
function Degrees(r)
|
||||
function Exp(n)
|
||||
function Frac(n)
|
||||
function Hex$(n)
|
||||
function HexVal(n$)
|
||||
function Int(n)
|
||||
function Log(n)
|
||||
function Max(a, b)
|
||||
function Min(a, b)
|
||||
function OrBit(a, b)
|
||||
function Radians(d)
|
||||
function Randomize(n)
|
||||
function Rand(n)
|
||||
function Round(n)
|
||||
function Sign(n)
|
||||
function Sin(n)
|
||||
function Sqrt(n)
|
||||
function Tan(n)
|
||||
function XOrBit(a, b)
|
||||
'Strings
|
||||
function Asc(c$)
|
||||
function Chr$(n)
|
||||
function Insert$(src$, tgt$, pos)
|
||||
function InStr(src$, substr$)
|
||||
function LCase$(src$)
|
||||
function Left$(src$, n)
|
||||
function Length(src$)
|
||||
function Len(src$)
|
||||
function LTrim$(src$)
|
||||
function Mid$(src$, start, n)
|
||||
function ReplaceSubstr$(src$, rpc$, pos)
|
||||
function Replace$(src$, tgt$, rpc$)
|
||||
function Reverse$(src$)
|
||||
function Right$(src$, n)
|
||||
function RTrim$(src$)
|
||||
function StringFill$(src$, n)
|
||||
function Str$(n)
|
||||
function Str_F$(n)
|
||||
function Str_S$(n)
|
||||
function Tally(src$, substr$)
|
||||
function Trim$(src$)
|
||||
function UCase$(src$)
|
||||
function Val(n$)
|
||||
'Stacks
|
||||
sub Stack_N(n)
|
||||
sub Stack_S(n)
|
||||
sub Push_N(n)
|
||||
function Pop_N()
|
||||
sub Push_S(s$)
|
||||
function Pop_S$()
|
||||
function Stack_Size_N()
|
||||
function Stack_Size_S()
|
||||
'File I/O
|
||||
function FileOpen(stream, fileName$, mode)
|
||||
sub FileClose(stream)
|
||||
function ReadByte(stream)
|
||||
sub WriteByte(stream, byte)
|
||||
function ReadLine$(stream)
|
||||
sub Write(stream, txt$)
|
||||
sub WriteLine(stream, txt$)
|
||||
sub CopyFile(src$, dst$)
|
||||
function RemoveFile(fileName$)
|
||||
function FileExists(fileName$)
|
||||
function MoveFile(src$, dst$)
|
||||
function RenameFile(src$, dst$)
|
||||
function FileLength(fileName$)
|
||||
function Tell(stream)
|
||||
function Seek(stream, pos)
|
||||
function EOF(stream)
|
||||
function FreeFile()
|
||||
'Directories
|
||||
sub ChangeDir(p$)
|
||||
function DirExists(p$)
|
||||
function DirFirst$()
|
||||
function Dir$()
|
||||
function DirNext$()
|
||||
function MakeDir(p$)
|
||||
function RemoveDir(p$)
|
||||
'Date and Time
|
||||
function Date$()
|
||||
function Easter$(year)
|
||||
function Ticks()
|
||||
function Time$()
|
||||
function Timer()
|
||||
sub Wait(m_sec)
|
||||
'Window Management
|
||||
sub WindowOpen(win, title$, x, y, w, h, flag, vsync)
|
||||
sub WindowClose(win)
|
||||
sub RaiseWindow(win)
|
||||
sub Window(win)
|
||||
sub Update()
|
||||
sub Cls()
|
||||
sub SetClearColor(c)
|
||||
sub ShowWindow(win)
|
||||
sub HideWindow(win)
|
||||
sub SetWindowTitle(win, title$)
|
||||
function WindowTitle$(win)
|
||||
sub SetWindowPosition(win, x, y)
|
||||
sub GetWindowPosition(win, byref x, byref y)
|
||||
sub SetWindowSize(win, w, h)
|
||||
sub GetWindowSize(win, byref w, byref h)
|
||||
sub SetWindowMinSize(win, w, h)
|
||||
sub GetWindowMinSize(win, byref w, byref h)
|
||||
sub SetWindowMaxSize(win, w, h)
|
||||
sub GetWindowMaxSize(win, byref w, byref h)
|
||||
function WindowIsFullscreen(win)
|
||||
function WindowIsVisible(win)
|
||||
function WindowIsBordered(win)
|
||||
function WindowIsResizable(win)
|
||||
function WindowIsMinimized(win)
|
||||
function WindowIsMaximized(win)
|
||||
function WindowHasInputFocus(win)
|
||||
function WindowHasMouseFocus(win)
|
||||
sub SetWindowFullscreen(win, flag)
|
||||
sub MaximizeWindow(win)
|
||||
sub MinimizeWindow(win)
|
||||
sub SetWindowBorder(win, flag)
|
||||
sub WindowClip(slot, x, y, w, h)
|
||||
function WindowExists(win)
|
||||
function NumWindows()
|
||||
function WindowEvent_Close(win)
|
||||
function WindowEvent_Maximize(win)
|
||||
function WindowEvent_Minimize(win)
|
||||
function ActiveWindow()
|
||||
function FPS()
|
||||
sub SetWindowIcon(win, slot)
|
||||
'Canvases
|
||||
sub CanvasOpen(c_num, w, h, viewport_x, viewport_y, viewport_w, viewport_h, mode)
|
||||
sub CanvasClose(c_num)
|
||||
sub SetCanvasVisible(c_num, flag)
|
||||
function CanvasIsVisible(c_num)
|
||||
sub SetCanvasViewport(cnum, x, y, w, h)
|
||||
sub GetCanvasViewport(c_num, byref x, byref y, byref w, byref h)
|
||||
sub Canvas(c_num)
|
||||
sub SetCanvasOffset(c_num, x, y)
|
||||
sub GetCanvasOffset(c_num, byref x, byref y)
|
||||
sub GetCanvasSize(c_num, byref w, byref h)
|
||||
sub ClearCanvas()
|
||||
sub SetCanvasAlpha(c_num, a)
|
||||
function CanvasAlpha(c_num)
|
||||
function SetCanvasBlendMode(c_num, blend_mode)
|
||||
function CanvasBlendMode(c_num)
|
||||
function SetCanvasColorMod(c_num, c)
|
||||
function CanvasColorMod(c_num)
|
||||
sub CopyCanvas(src, x, y, w, h, dst, dx, dy)
|
||||
sub CloneCanvas(src, dst)
|
||||
sub SetCanvasZ(c_num, z)
|
||||
function CanvasZ(c_num)
|
||||
sub CanvasClip(slot, x, y, w, h, flag)
|
||||
function ActiveCanvas()
|
||||
'Graphics Primitives
|
||||
sub Box(x1, y1, x2, y2)
|
||||
sub BoxFill(x1, y1, x2, y2)
|
||||
sub Circle(x,y,radius)
|
||||
sub CircleFill(x,y,radius)
|
||||
sub Ellipse(x,y,rx,ry)
|
||||
sub EllipseFill(x,y,rx,ry)
|
||||
sub FloodFill(x,y)
|
||||
function GetPixel(x,y)
|
||||
sub SetColor(c)
|
||||
sub Line(x1, y1, x2, y2)
|
||||
sub Poly(n, byref x, byref y)
|
||||
sub PolyFill(n, byref x, byref y)
|
||||
sub Rect(x, y, w, h)
|
||||
sub RectFill(x, y, w, h)
|
||||
sub RoundRect(x, y, w, h, r)
|
||||
sub RoundRectFill(x, y, w, h, r)
|
||||
function RGB(r,g,b)
|
||||
function RGBA(r,g,b,a)
|
||||
sub PSet(x,y)
|
||||
'Images
|
||||
sub LoadImage(slot, img$)
|
||||
sub LoadImage_Ex(slot, img$, colkey)
|
||||
sub ImageFromBuffer(slot, w, h, byref buffer)
|
||||
sub ImageFromBuffer_Ex(slot, w, h, byref buffer, colkey)
|
||||
sub BufferFromImage(slot, byref buffer)
|
||||
function ImageExists(slot)
|
||||
sub ColorKey(slot, c)
|
||||
sub CopyImage(src, dst)
|
||||
sub DeleteImage(slot)
|
||||
sub SetImageAlpha(slot, a)
|
||||
function ImageAlpha(slot)
|
||||
sub GetImageSize(slot, byref w, byref h)
|
||||
function SetImageBlendMode(slot, blend_mode)
|
||||
function ImageBlendMode(slot)
|
||||
function SetImageColorMod(slot, c)
|
||||
function ImageColorMod(slot)
|
||||
sub DrawImage(slot, x, y)
|
||||
sub DrawImage_Blit(slot, x, y, src_x, src_y, src_w, src_h)
|
||||
sub DrawImage_Blit_Ex(slot, x, y, w, h, src_x, src_y, src_w, src_h)
|
||||
sub DrawImage_Rotate(slot, x, y, angle)
|
||||
sub DrawImage_Rotate_Ex(slot, x, y, src_x, src_y, src_w, src_h, angle)
|
||||
sub DrawImage_Zoom(slot, x, y, zx, zy)
|
||||
sub DrawImage_Zoom_Ex(slot, x, y, src_x, src_y, src_w, src_h, zx, zy)
|
||||
sub DrawImage_Rotozoom(slot, x, y, angle, zx, zy)
|
||||
sub DrawImage_Rotozoom_Ex(slot, x, y, src_x, src_y, src_w, src_h, angle, zx, zy)
|
||||
sub DrawImage_Flip(slot, x, y, h, v)
|
||||
sub DrawImage_Flip_Ex(slot, x, y, src_x, src_y, src_w, src_h, h, v)
|
||||
'Keyboard and Mouse
|
||||
function InKey()
|
||||
function Key(key_code)
|
||||
function WaitKey()
|
||||
sub HideMouse()
|
||||
sub ShowMouse()
|
||||
function MouseIsVisible()
|
||||
sub GetMouse(byref x, byref y, byref mb1, byref mb2, byref mb3)
|
||||
function MouseX()
|
||||
function MouseY()
|
||||
function MouseButton(mb)
|
||||
sub GetMouseWheel(byref x_axis, byref y_axis)
|
||||
function MouseWheelX()
|
||||
function MouseWheelY()
|
||||
'Sound and Music
|
||||
sub SoundFromBuffer(slot, byref buffer, buffer_size, vol)
|
||||
sub LoadSound(slot, snd_file$)
|
||||
sub LoadMusic(music_file$)
|
||||
sub PlaySound(slot, channel, loops)
|
||||
sub PlaySoundTimed(slot, channel, loops, ms)
|
||||
sub PlayMusic(mLoops)
|
||||
sub PauseSound(channel)
|
||||
sub ResumeSound(channel)
|
||||
sub PauseMusic()
|
||||
sub ResumeMusic()
|
||||
sub DeleteSound(slot)
|
||||
sub DeleteMusic()
|
||||
sub FadeMusicIn(fade_time, loops)
|
||||
sub FadeMusicOut(fade_time)
|
||||
function MusicExists()
|
||||
sub SetMusicVolume(vol)
|
||||
function MusicVolume()
|
||||
sub SetMusicPosition(pos)
|
||||
function MusicPosition()
|
||||
sub RewindMusic()
|
||||
sub SetSoundChannels(max_channels)
|
||||
function NumSoundChannels()
|
||||
function SoundIsEnabled()
|
||||
function SoundExists(slot)
|
||||
sub SetChannelVolume(channel, vol)
|
||||
function ChannelVolume(channel)
|
||||
sub SetSoundVolume(slot, vol)
|
||||
function SoundVolume(slot)
|
||||
sub StopMusic()
|
||||
sub StopSound(channel)
|
||||
function SetChannelPanning(channel, left_value, right_value)
|
||||
function SetChannelDistance(channel, dist_value)
|
||||
function ChannelIsPlaying(channel)
|
||||
function ChannelIsPaused(channel)
|
||||
'Joysticks
|
||||
function NumJoysticks()
|
||||
function NumJoyAxes(joy_num)
|
||||
function NumJoyButtons(joy_num)
|
||||
function NumJoyHats(joy_num)
|
||||
function NumJoyTrackBalls(joy_num)
|
||||
function JoyAxis(joy_num, joy_axis)
|
||||
function JoyButton(joy_num, joy_button)
|
||||
function JoyHat(joy_num, joy_hat)
|
||||
sub GetJoyTrackBall(joy_num, ball, byref dx, byref dy)
|
||||
function JoyName$(joy_num)
|
||||
function JoystickIsConnected(joy_num)
|
||||
'Screen Console
|
||||
sub GetCursor(byref x, byref y)
|
||||
sub PrintS(txt$)
|
||||
function InputS$(prompt$)
|
||||
function ZoneInputS$(x, y, w, h)
|
||||
sub Locate(x, y)
|
||||
'Text Editing
|
||||
sub ReadInput_Start()
|
||||
sub ReadInput_Stop()
|
||||
function ReadInput_Text$()
|
||||
sub ReadInput_SetText(txt$)
|
||||
sub ReadInput_ToggleBackspace(flag)
|
||||
'Text Drawing
|
||||
sub LoadFont(slot, fnt_file$, size)
|
||||
sub DeleteFont(slot)
|
||||
function FontIsLoaded(slot)
|
||||
sub Font(slot)
|
||||
sub SetFontStyle(slot, style)
|
||||
sub DrawText(txt$, x, y)
|
||||
sub DrawText_Shaded(txt$, x, y, fg_color, bg_color)
|
||||
sub DrawText_Blended(txt$, x, y)
|
||||
sub RenderText(slot, txt$)
|
||||
sub GetTextSize(slot, txt$, byref w, byref h)
|
||||
'Touch Events
|
||||
function TouchPressure()
|
||||
sub GetTouch(byref status, byref x, byref y, byref dx, byref dy)
|
||||
sub GetMultiTouch(byref status, byref x, byref y, byref fingers, byref dist, byref theta)
|
||||
sub GetTouchFinger(finger, byref x, byref y, byref pressure)
|
||||
function NumFingers()
|
||||
'Networking
|
||||
function CheckSockets(timeout_ms)
|
||||
function TCP_SocketReady(socket)
|
||||
function UDP_SocketReady(socket)
|
||||
function TCP_SocketOpen(socket, host$, port)
|
||||
sub TCP_SocketClose(socket)
|
||||
function TCP_RemoteHost(socket)
|
||||
function TCP_RemotePort(socket)
|
||||
function TCP_GetData(socket, ByRef sData$, numBytes)
|
||||
sub TCP_SendData(socket, sData$)
|
||||
function TCP_AcceptSocket(server, client)
|
||||
function UDP_SocketOpen(socket, port)
|
||||
function UDP_SocketClose(socket)
|
||||
function UDP_GetData(socket, byref sData$, byref host$, byref port)
|
||||
function UDP_Length()
|
||||
function UDP_MaxLength()
|
||||
function UDP_RemoteHost$(socket)
|
||||
function UDP_RemotePort(socket)
|
||||
sub UDP_SendData(socket, sData$, host$, port)
|
||||
'Video Playback
|
||||
sub LoadVideo(vid$)
|
||||
sub PlayVideo(vLoops)
|
||||
sub PauseVideo()
|
||||
sub StopVideo()
|
||||
sub SetVideoPosition(pos)
|
||||
sub ResumeVideo()
|
||||
function VideoPosition()
|
||||
sub DeleteVideo()
|
||||
function VideoIsPlaying()
|
||||
function VideoEnd()
|
||||
sub GetVideoStats(vFile$, byref vLen, byref vfps, byref frame_w, byref frame_h)
|
||||
sub SetVideoDrawRect(x, y, w, h)
|
||||
sub GetVideoDrawRect(byref x, byref y, byref w, byref h)
|
||||
sub GetVideoSize(byref w, byref h)
|
||||
function VideoExists()
|
||||
sub SetVideoAlpha(a)
|
||||
'Operating System
|
||||
function System(cmd$)
|
||||
function OS$()
|
||||
function Command$(arg)
|
||||
function NumCommands()
|
||||
function Env$(v$)
|
||||
sub SetEnv(var$, value$, overwrite)
|
||||
function PrefPath$(org_name$, app_name$)
|
||||
function Android_GetExternalStoragePath$()
|
||||
function Android_GetExternalStorageState()
|
||||
function Android_GetInternalStoragePath$()
|
||||
function Android_JNI_Message$(arg$)
|
||||
function Runtime_Utility_Message$(arg$)
|
||||
'Clipboard
|
||||
function ClipboardText$()
|
||||
sub SetClipboardText(txt$)
|
||||
function HasClipboardText()
|
||||
|
||||
'v3.12
|
||||
Sub GetDesktopDisplayMode(index, ByRef w, ByRef h, ByRef freq)
|
||||
Sub DrawImage_Transform(slot, x, y, w, h, src_x, src_y, src_w, src_h, angle, center_x, center_y, flip_h, flip_v)
|
||||
Sub GetPowerInfo(ByRef status, ByRef secs, ByRef pct)
|
||||
Function SystemRam()
|
||||
Function SetRenderScaleQuality(n)
|
||||
Function EvalJS$(js_code$) 'Only useable in Emscripten
|
||||
Function GetRenderScaleQuality()
|
||||
|
||||
'v3.14
|
||||
sub GetGlobalMouse(ByRef x, ByRef y, ByRef mb1, ByRef mb2, ByRef mb3)
|
||||
function GlobalMouseX()
|
||||
function GlobalMouseY()
|
||||
sub GetAccel(accel_num, ByRef x, ByRef y, ByRef z)
|
||||
function AccelName$(accel_num)
|
||||
function NumAccels()
|
||||
sub GetGyro(gyro_num, ByRef x, ByRef y, ByRef z)
|
||||
function GyroName$(gyro_num)
|
||||
function NumGyros()
|
||||
sub JoyRumblePlay(joy_num, strength, duration)
|
||||
sub JoyRumbleStop(joy_num)
|
||||
function JoystickIsHaptic(joy_num)
|
||||
function WriteByteBuffer(stream, ByRef buf, buf_size)
|
||||
function ReadByteBuffer(stream, ByRef buf, buf_size)
|
||||
function WindowEvent_Resize(win)
|
||||
sub SetWindowAutoClose( win, exit_on_close )
|
||||
sub SetWindowResizable(win, flag) 'new
|
||||
function SystemReturnStdOut$(cmd$) 'new
|
||||
function WindowMode(visible, fullscreen, resizable, borderless, highDPI)
|
||||
function WindowFlags(win)
|
||||
sub RestoreWindow(win)
|
||||
sub UpdateAllWindows() 'new
|
||||
function QueryAudioSpec(ByRef freq, ByRef format, ByRef channels) 'new
|
||||
|
||||
'v3.15
|
||||
function MusicIsPlaying()
|
||||
|
||||
'v3.19
|
||||
function DrawGeometry(slot, num_vertices, ByRef vertices, num_indices, ByRef Indices)
|
||||
|
||||
'v3.20
|
||||
function Size(s$)
|
||||
function BufferFromString(s$, ByRef buffer)
|
||||
function StringFromBuffer$(ByRef buffer, buffer_size)
|
||||
sub GrabInput(flag)
|
||||
function GrabbedWindow()
|
||||
sub WarpMouse(x, y)
|
||||
sub WarpMouseGlobal(x, y)
|
||||
sub SetMouseZone(x, y, w, h)
|
||||
sub ClearMouseZone()
|
||||
sub SetWindowAlwaysOnTop(win, flag)
|
||||
sub SetMouseRelative(flag)
|
||||
sub SetWindowVSync(win, flag)
|
||||
function OpenURL(url$)
|
||||
function APIVersion$()
|
||||
function FlashWindow(win)
|
||||
function MessageBox(title$, msg$)
|
||||
sub NumberArrayCopy(ByRef src, ByRef dst)
|
||||
sub StringArrayCopy(ByRef src$, ByRef dst$)
|
||||
sub ArrayCopy(ByRef src, ByRef dst)
|
||||
sub NumberArrayFill(ByRef src, fdata)
|
||||
sub StringArrayFill(ByRef src$, fdata$)
|
||||
sub ArrayFill(ByRef src, fdata)
|
||||
function Runtime$()
|
||||
|
||||
'More v3.20 (Matrices and Parrallism)
|
||||
sub DimMatrix(m, m_rows, m_cols, preserve_flag)
|
||||
function AddMatrix(mA, mB, mC)
|
||||
function AugmentMatrix (mA, mB, mC)
|
||||
sub CopyMatrix(mA, mB)
|
||||
function InsertMatrixColumns(mA, c, num_cols)
|
||||
function InsertMatrixRows(mA, r, num_rows)
|
||||
function MultiplyMatrix (mA, mB, mC)
|
||||
function CubeMatrix(mA, mB)
|
||||
function DeleteMatrixColumns(mA, c, num_cols)
|
||||
function DeleteMatrixRows(mA, r, num_rows)
|
||||
sub ClearMatrix(mA)
|
||||
function ClearMatrixColumns (mA, c, num_cols)
|
||||
function ClearMatrixRows(mA, r, num_rows)
|
||||
sub FillMatrix(mA, v)
|
||||
function FillMatrixColumns(mA, c, num_cols, v)
|
||||
function FillMatrixRows(mA, r, num_rows, v)
|
||||
function CopyMatrixColumns(mA, mB, c, num_cols)
|
||||
function CopyMatrixRows (mA, mB, r, num_rows)
|
||||
sub IdentityMatrix(mA, n)
|
||||
function SolveMatrix(mA, mB, mC)
|
||||
function IsEqualMatrix(mA, mB, tolerance)
|
||||
function Determinant(mA)
|
||||
function AdjointMatrix(mA, mB)
|
||||
function InvertMatrix(mA, mB)
|
||||
sub MatrixFromBuffer(mA, r, c, ByRef buffer)
|
||||
sub GetMatrix(ByRef buffer, mA)
|
||||
sub RandomizeMatrix(mA, vmin, vmax)
|
||||
function MatrixValue(mA, r, c)
|
||||
sub SetMatrixValue(mA, r, c, v)
|
||||
sub ScalarMatrix (mA, mB, s_value)
|
||||
function ScalarMatrixColumns(mA, mB, c, num_cols, s_value)
|
||||
function ScalarMatrixRows(mA, mB, r, num_rows, s_value)
|
||||
function SquareMatrix(mA, mB)
|
||||
sub SubMatrix(mA, r, c)
|
||||
function SubtractMatrix (mA, mB, mC)
|
||||
sub SwapMatrix(mA, mB)
|
||||
function SwapMatrixColumn(mA, C1, C2)
|
||||
function SwapMatrixRow(mA, R1, R2)
|
||||
function TransposeMatrix(mA, mB)
|
||||
function UnAugmentMatrix(mA, mB, mC)
|
||||
sub ZeroMatrix(mA)
|
||||
|
||||
sub GetMatrixSize(mA, ByRef r, ByRef c)
|
||||
function SetMatrixProcess(p_num) 'Set to -1 for main thread
|
||||
|
||||
|
||||
'ERROR_FLAG - MATRIX_ON_ERROR_STOP, MATRIX_ON_ERROR_WAIT, MATRIX_ON_ERROR_CONTINUE
|
||||
function ProcessOpen(p_num) 'stops and locks mutex, and clears queue before changing mode
|
||||
sub SetProcessErrorMode(p_num, error_mode)
|
||||
function ProcessError(p_num)
|
||||
sub ProcessWait(p_num) 'waits for all calculations to complete and lock matrix mutex
|
||||
sub ProcessWaitAll() 'waits for all process to finish
|
||||
sub ProcessContinue(p_num) 'unlock mutex
|
||||
sub ProcessStop(p_num) 'stops after current calculation its working on and lock mutex
|
||||
sub ProcessClear(p_num) 'locks mutex and clears matrix queue
|
||||
function ProcessClose(p_num)
|
||||
function ProcessErrorMode(p_num)
|
||||
sub ProcessSleep(p_num, msec)
|
||||
function ProcessExists(p_num)
|
||||
sub ProcessStopAll()
|
||||
sub ProcessContinueAll()
|
||||
function ProcessQueueSize(p_num)
|
||||
|
||||
function NumCPUs()
|
||||
|
||||
'v3.21
|
||||
sub GetProjectionGeometry(cam_dist, mA, f_vertex_count, ByRef columns, ByRef uv, graph_offset_x, graph_offset_y, v_color, ByRef vertex_count, ByRef vertex2D, ByRef index_count, ByRef index, ByRef clip_dist, ByRef min_x, ByRef min_y, ByRef max_x, ByRef max_y)
|
||||
function CalculateFaceZ(cam_dist, graph_offset_x, graph_offset_y, view_w, view_h, view_depth, mA, f_vertex_count, ByRef columns, ByRef face_min_z, ByRef face_max_z, ByRef z_avg)
|
||||
function SetChannelSpacePosition(channel, angle, distance)
|
||||
function SaveBMP(img, file$)
|
||||
function SavePNG(img, file$)
|
||||
function SaveJPG(img, file$)
|
||||
Function GetLineIntersection(p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y, ByRef i_x, ByRef i_y)
|
||||
Function Interpolate(min_a, max_a, mid_a, min_b, max_b)
|
||||
Function ATan2(y, x)
|
||||
function PointInQuad(x, y, x1, y1, x2, y2, x3, y3, x4, y4)
|
||||
function PointInTri(x, y, x1, y1, x2, y2, x3, y3)
|
||||
Function Distance2D(x1, y1, x2, y2)
|
||||
Function Distance3D(x1, y1, z1, x2, y2, z2)
|
||||
function GetCircleLineIntersection(circle_x, circle_y, radius, x1, y1, x2, y2, ByRef ix1, ByRef iy1, ByRef ix2, ByRef iy2)
|
||||
function GetLinePlaneIntersection(ByRef line_point, ByRef line_direction, ByRef plane_point_1, ByRef plane_point_2, ByRef plane_point_3, ByRef intersection)
|
||||
sub IncrementMatrixRows(mA, mB, r, num_rows, value)
|
||||
sub IncrementMatrixColumns(mA, mB, c, num_cols, value)
|
||||
sub JoinMatrixRows(mA, mB, mC)
|
||||
sub JoinMatrixColumns(mA, mB, mC)
|
||||
64
rcbasic_build/env_resolve.h
Normal file
64
rcbasic_build/env_resolve.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef ENV_RESOLVE_H_INCLUDED
|
||||
#define ENV_RESOLVE_H_INCLUDED
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
#define RC_WINDOWS
|
||||
#elif __APPLE__
|
||||
#define RC_MAC
|
||||
#elif __linux__
|
||||
#define RC_LINUX
|
||||
#endif
|
||||
|
||||
#ifdef RC_WINDOWS
|
||||
#include <winbase.h>
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#endif // RC_WINDOWS
|
||||
|
||||
string rc_intern_env(string v)
|
||||
{
|
||||
#ifdef RC_WINDOWS
|
||||
char * val = new char[32767];
|
||||
int n = GetEnvironmentVariable(v.c_str(), val, 32767);
|
||||
string rtn = "";
|
||||
if (n>0)
|
||||
rtn = (string)val;
|
||||
delete val;
|
||||
return rtn;
|
||||
#else
|
||||
char * c = getenv(v.c_str());
|
||||
if(c != NULL)
|
||||
return (string) c;
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
string resolveEnvironmentVariables(string sdata)
|
||||
{
|
||||
string sdata_out = "";
|
||||
for(int i = 0; i < sdata.length(); i++)
|
||||
{
|
||||
if(sdata.substr(i, 2).compare("${")==0)
|
||||
{
|
||||
int end_index = sdata.substr(i+2).find_first_of("}");
|
||||
if(end_index == string::npos)
|
||||
{
|
||||
cout << "Error: Missing closing } in environment variable" << endl;
|
||||
return sdata_out;
|
||||
}
|
||||
string env_var = sdata.substr(i+2).substr(0, end_index);
|
||||
//cout << "env_var is " << env_var << endl;
|
||||
string env_value = rc_intern_env(env_var);
|
||||
sdata_out += env_value;
|
||||
i = (i+2) + end_index;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
sdata_out += sdata.substr(i, 1);
|
||||
}
|
||||
}
|
||||
return sdata_out;
|
||||
}
|
||||
|
||||
#endif // ENV_RESOLVE_H_INCLUDED
|
||||
231
rcbasic_build/file_directory.h
Normal file
231
rcbasic_build/file_directory.h
Normal file
@@ -0,0 +1,231 @@
|
||||
#ifndef FILE_DIRECTORY_H_INCLUDED
|
||||
#define FILE_DIRECTORY_H_INCLUDED
|
||||
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
#define RC_WINDOWS
|
||||
#elif __APPLE__
|
||||
#define RC_MAC
|
||||
#elif __linux__
|
||||
#define RC_LINUX
|
||||
#endif
|
||||
|
||||
|
||||
#include <sys/stat.h> //file system stuff
|
||||
#include <sys/types.h> //file system stuff
|
||||
#include <unistd.h> //file system stuff
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#ifdef RC_MAC
|
||||
#define RC_GETCWD
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef RC_WINDOWS
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
#endif // RC_WINDOWS
|
||||
|
||||
|
||||
#ifndef RC_WINDOWS
|
||||
|
||||
struct dirent *rc_entry;
|
||||
DIR *rc_dir;
|
||||
string rc_dir_path = "";
|
||||
|
||||
#else
|
||||
|
||||
struct dirent *rc_entry;
|
||||
string rc_dir;
|
||||
string rc_dir_path = "";
|
||||
HANDLE hfind;
|
||||
|
||||
#endif // RC_LINUX
|
||||
|
||||
|
||||
#ifndef RC_WINDOWS
|
||||
|
||||
|
||||
#ifdef RC_LINUX
|
||||
inline int rc_intern_dirChange(string ch_path)
|
||||
{
|
||||
if(chdir(ch_path.c_str())!=0)
|
||||
{
|
||||
cout << "Error: Could not change directory\n";
|
||||
return 2;
|
||||
}
|
||||
rc_dir_path = get_current_dir_name();
|
||||
return 0;
|
||||
}
|
||||
#endif // RC_LINUX
|
||||
|
||||
inline bool rc_intern_dirExist(string d_path)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
if(stat( d_path.c_str(), &info ) != 0)
|
||||
return false;
|
||||
else if(info.st_mode & S_IFDIR)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef RC_GETCWD
|
||||
string getcwd_str()
|
||||
{
|
||||
char *buffer = new char[MAXPATHLEN];
|
||||
getcwd(buffer,MAXPATHLEN);
|
||||
if(buffer != NULL)
|
||||
{
|
||||
string ret(buffer);
|
||||
delete[] buffer;
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline int rc_intern_dirChange(string ch_path)
|
||||
{
|
||||
if(chdir(ch_path.c_str())!=0)
|
||||
{
|
||||
cout << "Error: Could not change directory\n";
|
||||
return 2;
|
||||
}
|
||||
rc_dir_path = getcwd_str();
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline string rc_intern_dir()
|
||||
{
|
||||
string d = getcwd_str();
|
||||
//__android_log_print(ANDROID_LOG_ERROR, "RC_DEBUG_DIR", "%s", SDL_GetPrefPath("rcbasic","lucky"));
|
||||
if(d.compare("")==0)
|
||||
{
|
||||
//cout << "Could not get current directory" << endl;
|
||||
return "";
|
||||
}
|
||||
rc_dir_path = d;
|
||||
return d;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline string rc_intern_dir()
|
||||
{
|
||||
string d = get_current_dir_name();
|
||||
if(d.compare("")==0)
|
||||
{
|
||||
cout << "Could not get current directory" << endl;
|
||||
return "";
|
||||
}
|
||||
rc_dir_path = d;
|
||||
return d;
|
||||
}
|
||||
|
||||
#endif // RC_ANDROID
|
||||
|
||||
|
||||
#else
|
||||
|
||||
inline int rc_intern_dirChange(string dpath)
|
||||
{
|
||||
if(SetCurrentDirectory(dpath.c_str())==0)
|
||||
{
|
||||
cout << "Error: Could not change directory\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
DWORD nBufferLength = MAX_PATH;
|
||||
char szCurrentDirectory[MAX_PATH + 1];
|
||||
GetCurrentDirectory(nBufferLength, szCurrentDirectory);
|
||||
szCurrentDirectory[MAX_PATH] = '\0';
|
||||
|
||||
rc_dir_path = (string)szCurrentDirectory;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool dirExists(const std::string& dirName_in)
|
||||
{
|
||||
DWORD ftyp = GetFileAttributesA(dirName_in.c_str());
|
||||
if (ftyp == INVALID_FILE_ATTRIBUTES)
|
||||
return false; //something is wrong with your path!
|
||||
|
||||
if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
|
||||
return true; // this is a directory!
|
||||
|
||||
return false; // this is not a directory!
|
||||
}
|
||||
|
||||
inline int rc_intern_dirExist(string dpath)
|
||||
{
|
||||
return dirExists(dpath);
|
||||
}
|
||||
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA ffd;
|
||||
|
||||
inline string rc_intern_dir()
|
||||
{
|
||||
TCHAR buf[MAX_PATH];
|
||||
GetCurrentDirectory(MAX_PATH, buf);
|
||||
string d = buf;
|
||||
|
||||
if(d.compare("")==0)
|
||||
{
|
||||
cout << "Could not get current directory" << endl;
|
||||
return "";
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
#endif // RC_WINDOWS
|
||||
|
||||
|
||||
string rc_absFilePath(string file_path)
|
||||
{
|
||||
//cout << "file_path: " << file_path << endl;
|
||||
string cwd = rc_intern_dir();
|
||||
int start_index = 0;
|
||||
string::size_type bs_index = file_path.find_last_of("\\");
|
||||
string::size_type fs_index = file_path.find_last_of("/");
|
||||
int end_index = 0;
|
||||
|
||||
if(bs_index==string::npos && fs_index==string::npos)
|
||||
{
|
||||
#ifdef RC_WINDOWS
|
||||
return cwd + "\\" + file_path;
|
||||
#else
|
||||
return cwd + "/" + file_path;
|
||||
#endif // RC_WINDOWS
|
||||
}
|
||||
|
||||
end_index = ( (bs_index > fs_index || fs_index == string::npos) && bs_index != string::npos) ? bs_index : fs_index;
|
||||
|
||||
|
||||
if(rc_intern_dirExist(file_path.substr(0, end_index)))
|
||||
{
|
||||
rc_intern_dirChange(file_path.substr(0, end_index));
|
||||
|
||||
#ifdef RC_WINDOWS
|
||||
string abs_file_path = rc_intern_dir() + "\\" + file_path.substr(end_index+1);
|
||||
#else
|
||||
string abs_file_path = rc_intern_dir() + "/" + file_path.substr(end_index+1);
|
||||
#endif // RC_WINDOWS
|
||||
|
||||
rc_intern_dirChange(cwd);
|
||||
return abs_file_path;
|
||||
}
|
||||
|
||||
return file_path;
|
||||
}
|
||||
|
||||
|
||||
#endif // FILE_DIRECTORY_H_INCLUDED
|
||||
1248
rcbasic_build/identifier.h
Normal file
1248
rcbasic_build/identifier.h
Normal file
File diff suppressed because it is too large
Load Diff
48
rcbasic_build/keywords.h
Normal file
48
rcbasic_build/keywords.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef KEYWORDS_H_INCLUDED
|
||||
#define KEYWORDS_H_INCLUDED
|
||||
|
||||
using namespace std;
|
||||
|
||||
string keyWords[] = {
|
||||
"AND", //1
|
||||
"OR", //2
|
||||
"XOR", //3
|
||||
"EXIT", //4
|
||||
"MOD", //5
|
||||
"SHL", //6
|
||||
"SHR", //7
|
||||
"FUNCTION", //8
|
||||
"RETURN", //9
|
||||
"DIM", //10
|
||||
"END", //11
|
||||
"FOR", //12
|
||||
"TO", //13
|
||||
"STEP", //14
|
||||
"NEXT", //15
|
||||
"WHILE", //16
|
||||
"WEND", //17
|
||||
"DO", //18
|
||||
"LOOP", //19
|
||||
"UNTIL", //20
|
||||
"SELECT", //21
|
||||
"CASE", //22
|
||||
"DEFAULT", //23
|
||||
"IF", //24
|
||||
"ELSE", //25
|
||||
"THEN", //26
|
||||
"DELETE", //27
|
||||
"INCLUDE", //30
|
||||
"BYREF", //31
|
||||
"PRINT", //32
|
||||
"SUB", //33
|
||||
"NOT", //34
|
||||
"ELSEIF", //35
|
||||
"REDIM", //, //36
|
||||
"CONST", //37
|
||||
"ONCE", //38
|
||||
"CONTINUE", //39
|
||||
"AS", //40
|
||||
"TYPE" //41
|
||||
};
|
||||
|
||||
#endif // KEYWORDS_H_INCLUDED
|
||||
1173
rcbasic_build/main.cpp
Normal file
1173
rcbasic_build/main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
6079
rcbasic_build/parser.h
Normal file
6079
rcbasic_build/parser.h
Normal file
File diff suppressed because it is too large
Load Diff
1428
rcbasic_build/rc_builtin.h
Normal file
1428
rcbasic_build/rc_builtin.h
Normal file
File diff suppressed because it is too large
Load Diff
20
rcbasic_build/rc_debug.h
Normal file
20
rcbasic_build/rc_debug.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef RC_DEBUG_H_INCLUDED
|
||||
#define RC_DEBUG_H_INCLUDED
|
||||
|
||||
using namespace std;
|
||||
|
||||
string ERROR_MSG = "";
|
||||
|
||||
void rc_setError(string rc_error)
|
||||
{
|
||||
ERROR_MSG += rc_error + "\n";
|
||||
}
|
||||
|
||||
string rc_getError()
|
||||
{
|
||||
string error_out = ERROR_MSG;
|
||||
//ERROR_MSG = "";
|
||||
return error_out;
|
||||
}
|
||||
|
||||
#endif // RC_DEBUG_H_INCLUDED
|
||||
213
rcbasic_build/rc_global.h
Normal file
213
rcbasic_build/rc_global.h
Normal file
@@ -0,0 +1,213 @@
|
||||
#ifndef RC_GLOBAL_INCLUDED
|
||||
#define RC_GLOBAL_INCLUDED
|
||||
#include <inttypes.h>
|
||||
|
||||
#define CODE_SEGMENT 0
|
||||
#define DATA_SEGMENT 1
|
||||
|
||||
struct rc_label
|
||||
{
|
||||
string label_name="";
|
||||
uint64_t label_address=0;
|
||||
int label_segment = 0;
|
||||
};
|
||||
|
||||
class rc_vm_asm
|
||||
{
|
||||
public:
|
||||
vector<string> vm_code;
|
||||
vector<rc_label> label;
|
||||
int current_segment = 0;
|
||||
uint64_t current_address[2];
|
||||
uint64_t n_stack_count = 0;
|
||||
uint64_t s_stack_count = 0;
|
||||
uint64_t u_stack_count = 0;
|
||||
uint64_t max_n_stack_count = 0;
|
||||
uint64_t max_s_stack_count = 0;
|
||||
uint64_t max_u_stack_count = 0;
|
||||
|
||||
void push_back(string s)
|
||||
{
|
||||
s += " ";
|
||||
vm_code.push_back(s);
|
||||
if(s.substr(0,s.find_first_of(" ")).compare(".code")==0)
|
||||
{
|
||||
current_segment = CODE_SEGMENT;
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare(".data")==0)
|
||||
{
|
||||
//cout << "got data son" << endl;
|
||||
current_segment = DATA_SEGMENT;
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("label")==0)
|
||||
{
|
||||
rc_label current_label;
|
||||
s = s.substr(s.find_first_of(" "));
|
||||
s = s.substr(s.find_first_not_of(" "));
|
||||
current_label.label_name = s;
|
||||
current_label.label_address = current_address[current_segment];
|
||||
current_label.label_segment = current_segment;
|
||||
//cout << "got a mutha flippin label: " << current_label.label_name << " : " << current_label.label_segment << endl;
|
||||
label.push_back(current_label);
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("mov")==0 || s.substr(0,s.find_first_of(" ")).compare("mov$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("mov_r")==0 || s.substr(0,s.find_first_of(" ")).compare("mov_r$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("mov_type")==0 || s.substr(0,s.find_first_of(" ")).compare("add$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("add")==0 || s.substr(0,s.find_first_of(" ")).compare("sub")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("mul")==0 || s.substr(0,s.find_first_of(" ")).compare("div")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("pow")==0 || s.substr(0,s.find_first_of(" ")).compare("mod")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("shl")==0 || s.substr(0,s.find_first_of(" ")).compare("shr")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("and")==0 || s.substr(0,s.find_first_of(" ")).compare("or")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("xor")==0 || s.substr(0,s.find_first_of(" ")).compare("mov_arr$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("cmp")==0 || s.substr(0,s.find_first_of(" ")).compare("cmp$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("cmp_u")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_num1")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_str1")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_usr1")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("dim_type")==0 || s.substr(0,s.find_first_of(" ")).compare("dim_num1")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("dim_str1")==0 || s.substr(0,s.find_first_of(" ")).compare("loop_while")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("loop_until")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("while")==0 || s.substr(0,s.find_first_of(" ")).compare("mov_arr")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("ptr")==0 || s.substr(0,s.find_first_of(" ")).compare("ptr$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("redim1")==0 || s.substr(0,s.find_first_of(" ")).compare("redim1$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("for_offset_arr2")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_usr_n1")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_usr_s1")==0 || s.substr(0,s.find_first_of(" ")).compare("uref_ptr")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_usr_init1")==0 || s.substr(0,s.find_first_of(" ")).compare("preset_t")==0)
|
||||
{
|
||||
current_address[current_segment] += 17; //1 byte for instruction and 8 bytes for each argument
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("push")==0 )
|
||||
{
|
||||
n_stack_count++;
|
||||
if( (n_stack_count+1) > max_n_stack_count)
|
||||
max_n_stack_count = n_stack_count+1;
|
||||
current_address[current_segment] += 9;
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("push$")==0 )
|
||||
{
|
||||
s_stack_count++;
|
||||
if( (s_stack_count+1) > max_s_stack_count)
|
||||
max_s_stack_count = s_stack_count+1;
|
||||
current_address[current_segment] += 9;
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("push_t")==0 )
|
||||
{
|
||||
u_stack_count++;
|
||||
if( (u_stack_count+1) > max_u_stack_count)
|
||||
max_u_stack_count = u_stack_count+1;
|
||||
current_address[current_segment] += 9;
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("pop")==0)
|
||||
{
|
||||
n_stack_count--;
|
||||
current_address[current_segment] += 9;
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("pop$")==0)
|
||||
{
|
||||
s_stack_count--;
|
||||
current_address[current_segment] += 9;
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("pop_t")==0)
|
||||
{
|
||||
u_stack_count--;
|
||||
current_address[current_segment] += 9;
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("jmp")==0 || s.substr(0,s.find_first_of(" ")).compare("je")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("jne")==0 || s.substr(0,s.find_first_of(" ")).compare("jg")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("jge")==0 || s.substr(0,s.find_first_of(" ")).compare("jl")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("jle")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_num")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_str")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_usr")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_get")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_get$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_set")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_set$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("delete")==0 || s.substr(0,s.find_first_of(" ")).compare("delete$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("get_stack_size")==0 || s.substr(0,s.find_first_of(" ")).compare("get_stack_size$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("wend")==0 || s.substr(0,s.find_first_of(" ")).compare("loop")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("gosub")==0 || s.substr(0,s.find_first_of(" ")).compare("print")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("print$")==0 || s.substr(0,s.find_first_of(" ")).compare("func")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("not")==0 || s.substr(0,s.find_first_of(" ")).compare("next")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("pop_ptr")==0 || s.substr(0,s.find_first_of(" ")).compare("preset")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("preset$")==0 || s.substr(0,s.find_first_of(" ")).compare("for_offset_arr1")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("end_x")==0 || s.substr(0,s.find_first_of(" ")).compare("lval")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("lval$")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_usr_n")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_usr_s")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_usr_get")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("delete_t")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_usr_init")==0)
|
||||
{
|
||||
current_address[current_segment] += 9; //1 byte for instruction and 8 bytes a single argument
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("obj_num2")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_str2")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_usr2")==0 || s.substr(0,s.find_first_of(" ")).compare("dim_type1")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("dim_num2")==0 || s.substr(0,s.find_first_of(" ")).compare("dim_str2")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("redim2")==0 || s.substr(0,s.find_first_of(" ")).compare("redim2$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("for_offset_arr3")==0 || s.substr(0,s.find_first_of(" ")).compare("dbg")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_usr_n2")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_usr_s2")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_usr_init2")==0 || s.substr(0,s.find_first_of(" ")).compare("preset_t1")==0)
|
||||
{
|
||||
current_address[current_segment] += 25; //1 byte for instruction and 8 bytes for 3 arguments
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("dim_type2")==0 || s.substr(0,s.find_first_of(" ")).compare("dim_num3")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("dim_str3")==0 || s.substr(0,s.find_first_of(" ")).compare("for")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_num3")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_str3")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("redim3")==0 || s.substr(0,s.find_first_of(" ")).compare("redim3$")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_usr_n3")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_usr_s3")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("obj_usr3")==0 || s.substr(0,s.find_first_of(" ")).compare("obj_usr_init3")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("preset_t2")==0)
|
||||
{
|
||||
current_address[current_segment] += 33; //1 byte for instruction and 8 bytes for 4 arguments
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("dim_type3")==0 || s.substr(0,s.find_first_of(" ")).compare("preset_t3")==0)
|
||||
{
|
||||
current_address[current_segment] += 41; //1 byte for instruction and 8 bytes for 5 arguments
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("end")==0 || s.substr(0,s.find_first_of(" ")).compare("clear_obj")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("push_empty$")==0 || s.substr(0,s.find_first_of(" ")).compare("clear_stack")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("clear_stack$")==0 || s.substr(0,s.find_first_of(" ")).compare("do")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("pop_loop_stack")==0 || s.substr(0,s.find_first_of(" ")).compare("return")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("println")==0 || s.substr(0,s.find_first_of(" ")).compare("for_offset_0")==0 ||
|
||||
s.substr(0,s.find_first_of(" ")).compare("push_t_null")==0)
|
||||
{
|
||||
current_address[current_segment] += 1; //1 byte for instruction and no arguments
|
||||
}
|
||||
else if(s.substr(0,s.find_first_of(" ")).compare("dim_tfield")==0)
|
||||
{
|
||||
current_address[current_segment] += 57;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Unknown Instruction" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
vm_code.clear();
|
||||
}
|
||||
|
||||
uint64_t size()
|
||||
{
|
||||
return vm_code.size();
|
||||
}
|
||||
};
|
||||
|
||||
rc_vm_asm vm_asm;
|
||||
|
||||
//vector<string> vm_asm; //the generated opcodes for the current set of
|
||||
//vector<string> vm_data_asm;
|
||||
|
||||
vector<unsigned char> data_segment;
|
||||
vector<string> resolveID_id_reg;
|
||||
vector<int> resolveID_id_type;
|
||||
vector<int> resolveID_id_ut_index;
|
||||
vector<uint32_t> resolveID_id_vec_pos;
|
||||
|
||||
int getResolveReg(string arg)
|
||||
{
|
||||
for(int i = 0; i < resolveID_id_reg.size(); i++)
|
||||
{
|
||||
//cout << "compare (" << arg << " to " << resolveID_id_reg[i] << endl;
|
||||
if(resolveID_id_reg[i].compare(arg)==0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rid_count = 0;
|
||||
|
||||
#endif // RC_GLOBAL_INCLUDED
|
||||
72
rcbasic_build/rc_utility.h
Normal file
72
rcbasic_build/rc_utility.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef RC_UTILITY_H_INCLUDED
|
||||
#define RC_UTILITY_H_INCLUDED
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <ctype.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string rc_intToString(int a)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << a;
|
||||
string str = ss.str();
|
||||
ss.clear();
|
||||
return str;
|
||||
}
|
||||
|
||||
string rc_uint64ToString(uint64_t a)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << a;
|
||||
string str = ss.str();
|
||||
ss.clear();
|
||||
return str;
|
||||
}
|
||||
|
||||
int rc_stringToInt(string a)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << a;
|
||||
int i = 0;
|
||||
ss >> i;
|
||||
ss.clear();
|
||||
return i;
|
||||
}
|
||||
|
||||
string StringToUpper(string strToConvert)
|
||||
{//change each element of the string to upper case
|
||||
for(unsigned int i=0;i<strToConvert.length();i++)
|
||||
{
|
||||
strToConvert[i] = toupper(strToConvert[i]);
|
||||
}
|
||||
return strToConvert;//return the converted string
|
||||
}
|
||||
|
||||
string StringToLower(string strToConvert)
|
||||
{//change each element of the string to lower case
|
||||
for(unsigned int i=0;i<strToConvert.length();i++)
|
||||
{
|
||||
strToConvert[i] = tolower(strToConvert[i]);
|
||||
}
|
||||
return strToConvert;//return the converted string
|
||||
}
|
||||
|
||||
string rc_substr(string s, int start_pos=0, int num_char=0)
|
||||
{
|
||||
if(start_pos < 0)
|
||||
return "";
|
||||
if(start_pos >= s.length())
|
||||
return "";
|
||||
if( (start_pos+num_char) >= s.length())
|
||||
return s.substr(start_pos);
|
||||
return s.substr(start_pos, num_char);
|
||||
}
|
||||
|
||||
bool is_file_exist(const char *fileName)
|
||||
{
|
||||
std::ifstream infile(fileName);
|
||||
return infile.good();
|
||||
}
|
||||
|
||||
#endif // RC_UTILITY_H_INCLUDED
|
||||
1480
rcbasic_build/rc_vm_asm.h
Normal file
1480
rcbasic_build/rc_vm_asm.h
Normal file
File diff suppressed because it is too large
Load Diff
1052
rcbasic_build/tokenizer.h
Normal file
1052
rcbasic_build/tokenizer.h
Normal file
File diff suppressed because it is too large
Load Diff
285
rcbasic_build/vm_asm
Normal file
285
rcbasic_build/vm_asm
Normal file
@@ -0,0 +1,285 @@
|
||||
-------------------------
|
||||
|types of parameters
|
||||
-------------------------
|
||||
raw_number = starting character (0-9)
|
||||
n# = starting character n followed by # (# is a number denoting the number register to use)
|
||||
s# = starting character s followed by # (# is a number denoting the string register to use)
|
||||
u# = starting character u followed by # (# is a number denoting the user_type register to use)
|
||||
r# = starting character r followed by # (# is a number denoting the reference register to use) //references are set when obj_get or mov(34) or mov(38) is called
|
||||
!id = starting character is ! followed id (id is a number denoting the id vector position) //it can be used for any integer argument as well as id's
|
||||
@[data_address] = starting character is @ followed by the number specifying the offset in the data segment
|
||||
|
||||
----------------------------------------
|
||||
|SYSTEM AND VM OPERATION
|
||||
---------------------------------------
|
||||
|
||||
0 - end
|
||||
1 - dbg uint uint uint // arguments are (debug_function, file_index, line_number)
|
||||
|
||||
---------------------------------------
|
||||
|MOVING DATA
|
||||
----------------------------------------
|
||||
|
||||
32 - mov n# n#
|
||||
33 - mov n# raw_number
|
||||
34 - mov n# !id
|
||||
35 - mov !id n#
|
||||
|
||||
36 - mov$ s# s#
|
||||
37 - mov$ s# @[data_address]
|
||||
38 - mov$ s# !id
|
||||
39 - mov$ !id s#
|
||||
|
||||
40 - mov_r r# n#
|
||||
41 - mov_r$ r# s#
|
||||
|
||||
42 - mov_type u# u# //copy user types and arrays NOTE: This will do the same thing mov_r does by setting the reference pointed to by the first arg
|
||||
|
||||
--------------------------------------
|
||||
|OPERATORS
|
||||
-------------------------------------
|
||||
|
||||
43 - add$ s# s#
|
||||
|
||||
44 - add n# n#
|
||||
45 - sub n# n#
|
||||
46 - mul n# n#
|
||||
47 - div n# n#
|
||||
48 - pow n# n#
|
||||
49 - mod n# n#
|
||||
50 - shl n# n#
|
||||
51 - shr n# n#
|
||||
52 - and n# n#
|
||||
53 - or n# n#
|
||||
54 - xor n# n#
|
||||
55 - not n# n#
|
||||
|
||||
--------------------------------------
|
||||
|COMPARE AND JUMP
|
||||
--------------------------------------
|
||||
CMP_EQUAL
|
||||
CMP_NOT_EQUAL
|
||||
CMP_GREATER
|
||||
CMP_GREATER_EQUAL
|
||||
CMP_LESS
|
||||
CMP_LESS_EQUAL
|
||||
-------------------------------------
|
||||
|
||||
56 - cmp n# n#
|
||||
57 - cmp$ s# s#
|
||||
58 - cmp_u n# n#
|
||||
|
||||
59 - jmp n#
|
||||
60 - jmp @[address]
|
||||
61 - je n#
|
||||
62 - je @[address]
|
||||
63 - jne n#
|
||||
64 - jne @[address]
|
||||
65 - jg n#
|
||||
66 - jg @[address]
|
||||
67 - jge n#
|
||||
68 - jge @[address]
|
||||
69 - jl n#
|
||||
70 - jl @[address]
|
||||
71 - jle n#
|
||||
72 - jle @[address]
|
||||
|
||||
--------------------------------------
|
||||
|OBJECTS (USER TYPES AND ARRAYS)
|
||||
--------------------------------------
|
||||
OBJ_CURRENT_POSITION
|
||||
OBJ_CURRENT_TYPE
|
||||
--------------------------------------
|
||||
|
||||
73 - obj_num !id
|
||||
74 - obj_num1 !id n# (n# is the first dimension)
|
||||
75 - obj_num2 !id n# n#
|
||||
76 - obj_num3 !id n# n# n#
|
||||
|
||||
77 - obj_str !id
|
||||
78 - obj_str1 !id n# (n# is the first dimension)
|
||||
79 - obj_str2 !id n# n#
|
||||
80 - obj_str3 !id n# n# n#
|
||||
|
||||
81 - obj_usr !id
|
||||
82 - obj_usr1 !id n# (n# is the first dimension)
|
||||
83 - obj_usr2 !id n# n#
|
||||
84 - obj_usr3 !id n# n# n#
|
||||
|
||||
85 - obj_get n#
|
||||
86 - obj_get$ s#
|
||||
|
||||
87 - obj_set n#
|
||||
88 - obj_set s$
|
||||
|
||||
89 - clear_obj
|
||||
|
||||
90 - dim_type !id raw_number (user_type)
|
||||
91 - dim_type1 !id raw_number (user type) n# (dim1)
|
||||
92 - dim_type2 !id raw_number (user type) n# (dim1) n# (dim2)
|
||||
93 - dim_type3 !id raw_number (user type) n# (dim1) n# (dim2) n# (dim3)
|
||||
|
||||
94 - dim_num1 !id n# (dim1)
|
||||
95 - dim_num2 !id n# (dim1) n# (dim2)
|
||||
96 - dim_num3 !id n# (dim1) n# (dim2) n# (dim3)
|
||||
|
||||
97 - dim_str1 !id n# (dim1)
|
||||
98 - dim_str2 !id n# (dim1) n# (dim2)
|
||||
99 - dim_str3 !id n# (dim1) n# (dim2) n# (dim3)
|
||||
|
||||
--------------------------------------------
|
||||
|STACKS
|
||||
--------------------------------------------
|
||||
<STACK> NUM_STACK
|
||||
<STACK> STR_STACK
|
||||
--------------------------------------------
|
||||
|
||||
100 - delete !id
|
||||
101 - delete$ !id
|
||||
|
||||
102 - push n#
|
||||
103 - push !id
|
||||
|
||||
104 - push$ s#
|
||||
105 - push$ !id
|
||||
|
||||
106 - push_empty$
|
||||
|
||||
107 - pop n#
|
||||
108 - pop !id
|
||||
|
||||
109 - pop$ s$
|
||||
110 - pop$ !id
|
||||
|
||||
111 - get_stack_size n#
|
||||
112 - get_stack_size$ n#
|
||||
|
||||
113 - clear_stack
|
||||
114 - clear_stack$
|
||||
|
||||
---------------------------------------------
|
||||
|LOOP
|
||||
---------------------------------------------
|
||||
<STACK> LOOP_STACK
|
||||
---------------------------------------------
|
||||
|
||||
115 - while n#
|
||||
116 - wend @address 'using jmp in parser for now
|
||||
|
||||
117 - for !id n# (starting value) n# (ending value) n#(step value)
|
||||
118 - next @address
|
||||
|
||||
119 - do
|
||||
120 - loop
|
||||
121 - loop_while n#
|
||||
122 - loop_until n#
|
||||
|
||||
123 - pop_loop_stack
|
||||
|
||||
------------------------------------------
|
||||
|FUNCTIONS AND SUB ROUTINES
|
||||
------------------------------------------
|
||||
<STACK> FUNCTION_STACK
|
||||
------------------------------------------
|
||||
|
||||
124 - gosub @[address]
|
||||
125 - return
|
||||
|
||||
-----------------------------------------
|
||||
|POINTERS
|
||||
-----------------------------------------
|
||||
126 - ptr !id n#
|
||||
127 - ptr$ !id s#
|
||||
|
||||
------------------------------------------
|
||||
|ADDED STUFF 'Because I didn't plan this design that well
|
||||
------------------------------------------
|
||||
|
||||
128 - print n#
|
||||
129 - print$ s#
|
||||
130 - func raw_number (built-in function index)
|
||||
131 - push raw_number
|
||||
132 - println
|
||||
133 - mov n# %CMP_FLAG
|
||||
134 - cmp n# raw_number
|
||||
135 - mov_arr n# !id
|
||||
136 - mov_arr$ s# !id
|
||||
137 - pop_ptr n#
|
||||
138 - preset !id
|
||||
139 - preset$ !id
|
||||
|
||||
140 - redim1 !id n#
|
||||
141 - redim2 !id n# n#
|
||||
142 - redim3 !id n# n# n#
|
||||
|
||||
143 - redim1$ !id n#
|
||||
144 - redim2$ !id n# n#
|
||||
145 - redim3$ !id n# n# n#
|
||||
|
||||
146 - for_offset_arr1 n#
|
||||
147 - for_offset_arr2 n# n#
|
||||
148 - for_offset_arr3 n# n# n#
|
||||
|
||||
149 - for_offset_0
|
||||
|
||||
150 - end_x n#
|
||||
|
||||
151 - lval n#
|
||||
152 - lval !id
|
||||
153 - lval @[address]
|
||||
|
||||
154 - lval$ s#
|
||||
155 - lval$ !id
|
||||
|
||||
// ---- New in 4.0 ---------
|
||||
156 - obj_usr_n !id
|
||||
157 - obj_usr_n1 !id n#
|
||||
158 - obj_usr_n2 !id n# n#
|
||||
159 - obj_usr_n3 !id n# n# n#
|
||||
|
||||
160 - obj_usr_s !id
|
||||
161 - obj_usr_s1 !id n#
|
||||
162 - obj_usr_s2 !id n# n#
|
||||
163 - obj_usr_s3 !id n# n# n#
|
||||
|
||||
164 - obj_usr_get n#
|
||||
165 - obj_usr_get s#
|
||||
166 - obj_usr_get u# // gets the value and sets the reference
|
||||
|
||||
167 - uref_ptr !id u#
|
||||
|
||||
168 - mov_type !id u# //copy user types and arrays
|
||||
|
||||
169 - push_t u#
|
||||
170 - push_t !id
|
||||
|
||||
171 - pop_t u#
|
||||
172 - pop_t !id
|
||||
|
||||
173 - push_t_null
|
||||
|
||||
174 - delete_t !id
|
||||
|
||||
175 - dim_type u# raw_number (user_type)
|
||||
176 - dim_type1 u# raw_number (user type) n# (dim1)
|
||||
177 - dim_type2 u# raw_number (user type) n# (dim1) n# (dim2)
|
||||
178 - dim_type3 u# raw_number (user type) n# (dim1) n# (dim2) n# (dim3)
|
||||
|
||||
179 - dim_tfield raw_number (user_type) raw_number (member_type) raw_number (member_index) raw_number (dimensions) n# (dim1) n# (dim2) n# (dim3)
|
||||
|
||||
180 - obj_usr_init !id
|
||||
181 - obj_usr_init1 !id n# (n# is the first dimension)
|
||||
182 - obj_usr_init2 !id n# n#
|
||||
183 - obj_usr_init3 !id n# n# n#
|
||||
|
||||
184 - obj_usr_init u#
|
||||
185 - obj_usr_init1 u# n# (n# is the first dimension)
|
||||
186 - obj_usr_init2 u# n# n#
|
||||
187 - obj_usr_init3 u# n# n# n#
|
||||
|
||||
188 - preset_t !id raw_number (user_type)
|
||||
189 - preset_t1 !id raw_number (user_type) n#
|
||||
190 - preset_t2 !id raw_number (user_type) n# n#
|
||||
191 - preset_t3 !id raw_number (user_type) n# n# n#
|
||||
|
||||
|
||||
5653
rcbasic_runtime/main.cpp
Normal file
5653
rcbasic_runtime/main.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1417
rcbasic_runtime/rc_defines.h
Normal file
1417
rcbasic_runtime/rc_defines.h
Normal file
File diff suppressed because it is too large
Load Diff
822
rcbasic_runtime/rc_geometry.h
Normal file
822
rcbasic_runtime/rc_geometry.h
Normal file
@@ -0,0 +1,822 @@
|
||||
#include "rc_matrix.h"
|
||||
#include <cmath>
|
||||
|
||||
#ifndef RC_GEOMETRY_H_INCLUDED
|
||||
#define RC_GEOMETRY_H_INCLUDED
|
||||
|
||||
|
||||
// ------------------ 3D Transform Routines --------------------------------
|
||||
|
||||
|
||||
double CalculateFaceZ(double cam_dist, double graph_offset_x, double graph_offset_y, double view_w, double view_h, double view_depth, uint32_t mA, int f_vertex_count, double* columns, double* face_min_z, double* face_max_z, double* z_avg)
|
||||
{
|
||||
bool dbg = false;
|
||||
|
||||
if(f_vertex_count > 4)
|
||||
return -1;
|
||||
|
||||
|
||||
double vx, vy, vz[4];
|
||||
|
||||
int oi_count = 0;
|
||||
|
||||
|
||||
double n_face_min_z = MatrixValue(mA, 2, (uint32_t)columns[0]);
|
||||
double n_face_max_z = n_face_min_z;
|
||||
|
||||
|
||||
bool in_zx_range = false;
|
||||
bool in_zy_range = false;
|
||||
|
||||
double face_min_x = 0;
|
||||
double face_max_x = 0;
|
||||
|
||||
double face_min_y = 0;
|
||||
double face_max_y = 0;
|
||||
|
||||
bool zx_min_bound = false;
|
||||
bool zx_max_bound = false;
|
||||
|
||||
bool zy_min_bound = false;
|
||||
bool zy_max_bound = false;
|
||||
|
||||
double distance = 0;
|
||||
|
||||
double z_dist = 0; //C3D_CAMERA_LENS - z
|
||||
double off_x = graph_offset_x;
|
||||
double off_y = graph_offset_y;
|
||||
|
||||
double min_x = (0 - off_x) / cam_dist;
|
||||
double min_y = (view_h - off_y) / cam_dist * -1;
|
||||
|
||||
double max_x = (view_w - off_x) / cam_dist;
|
||||
double max_y = (0 - off_y) / cam_dist * -1;
|
||||
|
||||
double zx_min, zx_max, zy_min, zy_max;
|
||||
|
||||
for(int i = 0; i < f_vertex_count; i++)
|
||||
{
|
||||
vz[i] = MatrixValue(mA, 2, (uint32_t)columns[i]);
|
||||
vx = MatrixValue(mA, 0, (uint32_t)columns[i]);
|
||||
vy = MatrixValue(mA, 1, (uint32_t)columns[i]);
|
||||
|
||||
|
||||
distance = -1*vz[i];
|
||||
|
||||
if(distance >= 0 && distance < view_depth)
|
||||
{
|
||||
double d = cam_dist - (distance*-1);
|
||||
zx_min = min_x * d;
|
||||
zx_max = max_x * d;
|
||||
zy_min = min_y * d;
|
||||
zy_max = max_y * d;
|
||||
|
||||
in_zx_range = in_zx_range || (vx >= zx_min && vx < zx_max);
|
||||
in_zy_range = in_zy_range || (vy >= zy_min && vy < zy_max);
|
||||
|
||||
zx_min_bound = zx_min_bound || (vx < zx_min);
|
||||
zx_max_bound = zx_max_bound || (vx >= zx_max);
|
||||
|
||||
zy_min_bound = zy_min_bound || (vy < zy_min);
|
||||
zy_max_bound = zy_max_bound || (vy >= zy_max);
|
||||
}
|
||||
else if(vz[i] >= 0 && vz[i] < view_depth)
|
||||
{
|
||||
double d = cam_dist - (vz[i]*-1);
|
||||
zx_min = min_x * d;
|
||||
zx_max = max_x * d;
|
||||
zy_min = min_y * d;
|
||||
zy_max = max_y * d;
|
||||
|
||||
in_zx_range = in_zx_range || (vx >= zx_min && vx < zx_max);
|
||||
in_zy_range = in_zy_range || (vy >= zy_min && vy < zy_max);
|
||||
|
||||
zx_min_bound = zx_min_bound || (vx < zx_min);
|
||||
zx_max_bound = zx_max_bound || (vx >= zx_max);
|
||||
|
||||
zy_min_bound = zy_min_bound || (vy < zy_min);
|
||||
zy_max_bound = zy_max_bound || (vy >= zy_max);
|
||||
}
|
||||
|
||||
n_face_min_z = min(n_face_min_z, vz[i]);
|
||||
n_face_max_z = max(n_face_max_z, vz[i]);
|
||||
|
||||
}
|
||||
|
||||
in_zx_range = in_zx_range || (zx_min_bound && zx_max_bound);
|
||||
in_zy_range = in_zy_range || (zy_min_bound && zy_max_bound);
|
||||
|
||||
if( (!in_zx_range) || (!in_zy_range) )
|
||||
return -1;
|
||||
|
||||
//'if key(k_i) and actor = 1 then : print "face = ";face_num : end if
|
||||
|
||||
z_avg[0] = (n_face_min_z+n_face_max_z) / 2; //'This is some bullshit math to order the faces with out checking if they are obscured
|
||||
|
||||
face_min_z[0] = n_face_min_z;
|
||||
face_max_z[0] = n_face_max_z;
|
||||
|
||||
//C3D_Actor_Face_ZOrder[actor, face_num] = face_min_z
|
||||
|
||||
|
||||
if(face_min_z[0] >= cam_dist)
|
||||
return -1;
|
||||
else
|
||||
return (cam_dist - face_min_z[0]);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int GetLinePlaneIntersection(double* line_point, double* line_direction, double* plane_point_1, double* plane_point_2, double* plane_point_3, double* intersection)
|
||||
{
|
||||
//' """
|
||||
//' Calculates the intersection point of a line and a plane in 3D space.
|
||||
//'
|
||||
//' Parameters:
|
||||
//' line_point (tuple or list): a point on the line (x, y, z)
|
||||
//' line_direction (tuple or list): the direction vector of the line (x, y, z)
|
||||
//' plane_point_1 (tuple or list): one point on the plane (x, y, z)
|
||||
//' plane_point_2 (tuple or list): another point on the plane (x, y, z)
|
||||
//' plane_point_3 (tuple or list): a third point on the plane (x, y, z)
|
||||
//'
|
||||
//' Returns:
|
||||
//' intersection (tuple): the intersection point (x, y, z), or None if the line is parallel to the plane
|
||||
//' """
|
||||
//' # calculate the normal vector of the plane using the cross product of two vectors on the plane
|
||||
|
||||
double plane_vector_1[3], plane_vector_2[3], plane_normal[3];
|
||||
|
||||
plane_vector_1[0] = plane_point_2[0] - plane_point_1[0];
|
||||
plane_vector_1[1] = plane_point_2[1] - plane_point_1[1];
|
||||
plane_vector_1[2] = plane_point_2[2] - plane_point_1[2];
|
||||
|
||||
plane_vector_2[0] = plane_point_3[0] - plane_point_1[0];
|
||||
plane_vector_2[1] = plane_point_3[1] - plane_point_1[1];
|
||||
plane_vector_2[2] = plane_point_3[2] - plane_point_1[2];
|
||||
|
||||
plane_normal[0] = plane_vector_1[1] * plane_vector_2[2] - plane_vector_1[2] * plane_vector_2[1];
|
||||
plane_normal[1] = plane_vector_1[2] * plane_vector_2[0] - plane_vector_1[0] * plane_vector_2[2];
|
||||
plane_normal[2] = plane_vector_1[0] * plane_vector_2[1] - plane_vector_1[1] * plane_vector_2[0];
|
||||
|
||||
//'# calculate the scalar value of t using the line equation
|
||||
double t = ((plane_point_1[0] - line_point[0]) * plane_normal[0] + (plane_point_1[1] - line_point[1]) * plane_normal[1] + (plane_point_1[2] - line_point[2]) * plane_normal[2]);
|
||||
//'print "t1 = ";t
|
||||
t = t / (line_direction[0] * plane_normal[0] + line_direction[1] * plane_normal[1] + line_direction[2] * plane_normal[2]);
|
||||
//'print "t2 = ";(line_direction[0] * plane_normal[0] + line_direction[1] * plane_normal[1] + line_direction[2] * plane_normal[2])
|
||||
|
||||
//'# calculate the intersection point using the line equation
|
||||
intersection[0] = line_point[0] + t * line_direction[0];
|
||||
intersection[1] = line_point[1] + t * line_direction[1];
|
||||
intersection[2] = line_point[2] + t * line_direction[2];
|
||||
|
||||
//'# check if the intersection point is on the plane
|
||||
double plane_distance = abs((intersection[0] - plane_point_1[0]) * plane_normal[0] + (intersection[1] - plane_point_1[1]) * plane_normal[1] + (intersection[2] - plane_point_1[2]) * plane_normal[2]);
|
||||
if(plane_distance < 10^-6)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
double Distance3D(double x1, double y1, double z1, double x2, double y2, double z2)
|
||||
{
|
||||
return sqrt( pow((x2 - x1),2) + pow((y2 - y1),2) + pow((z2 - z1),2) );
|
||||
}
|
||||
|
||||
double Interpolate(double min_a, double max_a, double mid_a, double min_b, double max_b)
|
||||
{
|
||||
return ( (mid_a-min_a)/(max_a-min_a)) * (max_b-min_b) + min_b;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int GetLineIntersect(double p0_x, double p0_y, double p1_x, double p1_y, double p2_x, double p2_y, double p3_x, double p3_y, double* i_x, double* i_y)
|
||||
{
|
||||
double s1_x = p1_x - p0_x;
|
||||
double s1_y = p1_y - p0_y;
|
||||
double s2_x = p3_x - p2_x;
|
||||
double s2_y = p3_y - p2_y;
|
||||
|
||||
double n = ( (-1 * s2_x) * s1_y + s1_x * s2_y);
|
||||
|
||||
if(n == 0)
|
||||
return 0;
|
||||
|
||||
double s = ( (-1 * s1_y) * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / n;
|
||||
double t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / n;
|
||||
|
||||
i_x[0] = p0_x + (t * s1_x);
|
||||
i_y[0] = p0_y + (t * s1_y);
|
||||
|
||||
if(s >= 0 && s <= 1 && t >= 0 && t <= 1)
|
||||
{
|
||||
//' Collision detected
|
||||
return 1;
|
||||
}
|
||||
|
||||
//' No collision
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PointInQuad(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
|
||||
{
|
||||
//'"""
|
||||
//'Check if a point (x, y) is inside a quadrilateral defined by its four vertices (x1, y1), (x2, y2), (x3, y3), and (x4, y4).
|
||||
//'"""
|
||||
//'# Compute the cross products of vectors from the point to each vertex of the quadrilateral.
|
||||
//'# If all cross products have the same sign, the point is inside the quadrilateral.
|
||||
double cross1 = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1);
|
||||
double cross2 = (x - x2) * (y3 - y2) - (y - y2) * (x3 - x2);
|
||||
double cross3 = (x - x3) * (y4 - y3) - (y - y3) * (x4 - x3);
|
||||
double cross4 = (x - x4) * (y1 - y4) - (y - y4) * (x1 - x4);
|
||||
|
||||
if(cross1 >= 0 && cross2 >= 0 && cross3 >= 0 && cross4 >= 0)
|
||||
return 1;
|
||||
else if(cross1 <= 0 && cross2 <= 0 && cross3 <= 0 && cross4 <= 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PointInTri(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3)
|
||||
{
|
||||
//"""
|
||||
//Check if a point (x, y) is inside a triangle defined by its three vertices (x1, y1), (x2, y2), and (x3, y3).
|
||||
//"""
|
||||
//# Calculate the barycentric coordinates of the point with respect to the triangle vertices.
|
||||
double denominator = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3);
|
||||
|
||||
double alpha = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / denominator;
|
||||
double beta = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) / denominator;
|
||||
double gamma = 1 - alpha - beta;
|
||||
|
||||
//# Check if the barycentric coordinates are within the range [0, 1].
|
||||
if( (0 <= alpha && alpha <= 1) && (0 <= beta && beta <= 1) && (0 <= gamma && gamma <= 1) )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
double Distance2D(double x1, double y1, double x2, double y2)
|
||||
{
|
||||
return sqrt( pow((x2 - x1),2) + pow((y2 - y1),2) );
|
||||
}
|
||||
|
||||
double GetCircleLineIntersection(double cx, double cy, double r, double x1, double y1, double x2, double y2, double* ix1, double* iy1, double* ix2, double* iy2)
|
||||
{
|
||||
//'"""
|
||||
//'Calculate the intersection points between a line defined by two points (x1, y1) and (x2, y2),
|
||||
//'and a circle with center (cx, cy) and radius r.
|
||||
//'"""
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double a = pow(dx,2) + pow(dy,2);
|
||||
double b = 2 * (dx * (x1 - cx) + dy * (y1 - cy));
|
||||
double c = pow((x1 - cx),2) + pow((y1 - cy),2) - pow(r,2);
|
||||
|
||||
double discriminant = pow(b,2) - 4 * a * c;
|
||||
|
||||
if(discriminant < 0)
|
||||
{
|
||||
//'# No intersection points
|
||||
return 0;
|
||||
}
|
||||
else if( discriminant == 0 )
|
||||
{
|
||||
//'# One intersection point
|
||||
double t = -b / (2 * a);
|
||||
ix1[0] = x1 + t * dx;
|
||||
iy1[0] = y1 + t * dy;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//'# Two intersection points
|
||||
double t1 = (-b + sqrt(discriminant)) / (2 * a);
|
||||
double t2 = (-b - sqrt(discriminant)) / (2 * a);
|
||||
|
||||
ix1[0] = x1 + t1 * dx;
|
||||
iy1[0] = y1 + t1 * dy;
|
||||
ix2[0] = x1 + t2 * dx;
|
||||
iy2[0] = y1 + t2 * dy;
|
||||
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int CAMERA_LENS = 0;
|
||||
|
||||
// 'Returns number of points in clipped triangle Or 0 if no clipping was done
|
||||
int ClipTriangle(double* tri, double* uv, double* clipped_tri, double* clipped_uv)
|
||||
{
|
||||
|
||||
int clip_count = 0;
|
||||
|
||||
double lp[3], ld[3], p1[3], p2[3], p3[3], intersect[3];
|
||||
|
||||
double AB_dist, AC_dist, dist;
|
||||
|
||||
//'vec(lp, 20, 30, 265)
|
||||
//'vec(ld, 20 - lp[0], 20 - lp[1], 275 - lp[2])
|
||||
|
||||
int clip_dist = CAMERA_LENS-1;
|
||||
|
||||
p1[0] = -1;
|
||||
p1[1] = -1;
|
||||
p1[2] = clip_dist;
|
||||
|
||||
p2[0] = 1;
|
||||
p2[1] = 1;
|
||||
p2[2] = clip_dist;
|
||||
|
||||
p3[0] = 1;
|
||||
p3[1] = -1;
|
||||
p3[2] = clip_dist;
|
||||
|
||||
//'C3D_LinePlaneIntersection(lp, ld, p1, p2, p3, intersect)
|
||||
|
||||
double pt[9];
|
||||
double pt_uv[6];
|
||||
|
||||
double nc[9];
|
||||
double nc_uv[6];
|
||||
int non_clip_count = 0;
|
||||
|
||||
int c_index = 0;
|
||||
int pt_uv_index = 0;
|
||||
int nc_uv_index = 0;
|
||||
int uv_index = 0;
|
||||
|
||||
for(int i = 0; i <= 8; i+=3)
|
||||
{
|
||||
if( tri[i+2] >= clip_dist )
|
||||
{
|
||||
c_index = clip_count*3;
|
||||
pt[c_index] = tri[i];
|
||||
pt[c_index+1] = tri[i+1];
|
||||
pt[c_index+2] = tri[i+2];
|
||||
|
||||
pt_uv_index = clip_count*2;
|
||||
uv_index = i/3*2;
|
||||
pt_uv[pt_uv_index] = uv[uv_index];
|
||||
pt_uv[pt_uv_index+1] = uv[uv_index+1];
|
||||
|
||||
clip_count = clip_count + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
c_index = non_clip_count*3;
|
||||
nc[c_index] = tri[i];
|
||||
nc[c_index+1] = tri[i+1];
|
||||
nc[c_index+2] = tri[i+2];
|
||||
|
||||
nc_uv_index = non_clip_count*2;
|
||||
uv_index = i/3*2;
|
||||
nc_uv[nc_uv_index] = uv[uv_index];
|
||||
nc_uv[nc_uv_index+1] = uv[uv_index+1];
|
||||
|
||||
non_clip_count = non_clip_count + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(clip_count == 0 || clip_count == 3 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
switch(clip_count)
|
||||
{
|
||||
case 1:
|
||||
lp[0] = pt[0];
|
||||
lp[1] = pt[1];
|
||||
lp[2] = pt[2];
|
||||
|
||||
ld[0] = nc[0] - lp[0];
|
||||
ld[1] = nc[1] - lp[1];
|
||||
ld[2] = nc[2] - lp[2];
|
||||
|
||||
GetLinePlaneIntersection(&lp[0], &ld[0], &p1[0], &p2[0], &p3[0], &intersect[0]);
|
||||
|
||||
//'dim clipped_tri[3]
|
||||
|
||||
AB_dist = Distance3D(pt[0], pt[1], pt[2], nc[0], nc[1], nc[2]);
|
||||
AC_dist = Distance3D(pt[0], pt[1], pt[2], nc[3], nc[4], nc[5]);
|
||||
|
||||
//'AB
|
||||
clipped_tri[0] = intersect[0];
|
||||
clipped_tri[1] = intersect[1];
|
||||
clipped_tri[2] = intersect[2];
|
||||
|
||||
dist = Distance3D(pt[0], pt[1], pt[2], clipped_tri[0], clipped_tri[1], clipped_tri[2]);
|
||||
clipped_uv[0] = Interpolate(0, AB_dist, dist, pt_uv[0], nc_uv[0]);
|
||||
clipped_uv[1] = Interpolate(0, AB_dist, dist, pt_uv[1], nc_uv[1]);
|
||||
|
||||
//'B
|
||||
clipped_tri[3] = nc[0];
|
||||
clipped_tri[4] = nc[1];
|
||||
clipped_tri[5] = nc[2];
|
||||
|
||||
clipped_uv[2] = nc_uv[0];
|
||||
clipped_uv[3] = nc_uv[1];
|
||||
//'print "TEST: ";clipped_uv[2];", ";clipped_uv[3]
|
||||
|
||||
//'C
|
||||
clipped_tri[6] = nc[3];
|
||||
clipped_tri[7] = nc[4];
|
||||
clipped_tri[8] = nc[5];
|
||||
|
||||
clipped_uv[4] = nc_uv[2];
|
||||
clipped_uv[5] = nc_uv[3];
|
||||
|
||||
//'print "TEST(C): (";clipped_tri[6];", ";clipped_tri[7];", ";clipped_tri[8];") (";clipped_uv[4];", ";clipped_uv[5];")"
|
||||
|
||||
//'AB
|
||||
clipped_tri[9] = clipped_tri[0];
|
||||
clipped_tri[10] = clipped_tri[1];
|
||||
clipped_tri[11] = clipped_tri[2];
|
||||
|
||||
clipped_uv[6] = clipped_uv[0];
|
||||
clipped_uv[7] = clipped_uv[1];
|
||||
|
||||
//'C
|
||||
clipped_tri[12] = nc[3];
|
||||
clipped_tri[13] = nc[4];
|
||||
clipped_tri[14] = nc[5];
|
||||
|
||||
clipped_uv[8] = nc_uv[2];
|
||||
clipped_uv[9] = nc_uv[3];
|
||||
|
||||
ld[0] = nc[3] - lp[0];
|
||||
ld[1] = nc[4] - lp[1];
|
||||
ld[2] = nc[5] - lp[2];
|
||||
|
||||
GetLinePlaneIntersection(&lp[0], &ld[0], &p1[0], &p2[0], &p3[0], &intersect[0]);
|
||||
|
||||
//'AC
|
||||
clipped_tri[15] = intersect[0];
|
||||
clipped_tri[16] = intersect[1];
|
||||
clipped_tri[17] = intersect[2];
|
||||
|
||||
dist = Distance3D(pt[0], pt[1], pt[2], clipped_tri[15], clipped_tri[16], clipped_tri[17]);
|
||||
clipped_uv[10] = Interpolate(0, AC_dist, dist, pt_uv[0], nc_uv[2]);
|
||||
clipped_uv[11] = Interpolate(0, AC_dist, dist, pt_uv[1], nc_uv[3]);
|
||||
|
||||
return 6;
|
||||
|
||||
case 2:
|
||||
//'A is the no clip
|
||||
lp[0] = pt[0];
|
||||
lp[1] = pt[1];
|
||||
lp[2] = pt[2];
|
||||
|
||||
ld[0] = nc[0] - lp[0];
|
||||
ld[1] = nc[1] - lp[1];
|
||||
ld[2] = nc[2] - lp[2];
|
||||
|
||||
GetLinePlaneIntersection(&lp[0], &ld[0], &p1[0], &p2[0], &p3[0], &intersect[0]);
|
||||
|
||||
AB_dist = Distance3D(pt[0], pt[1], pt[2], nc[0], nc[1], nc[2]);
|
||||
AC_dist = Distance3D(pt[3], pt[4], pt[5], nc[0], nc[1], nc[2]);
|
||||
|
||||
//'A
|
||||
clipped_tri[0] = nc[0];
|
||||
clipped_tri[1] = nc[1];
|
||||
clipped_tri[2] = nc[2];
|
||||
|
||||
clipped_uv[0] = nc_uv[0];
|
||||
clipped_uv[1] = nc_uv[1];
|
||||
|
||||
//'AB
|
||||
clipped_tri[3] = intersect[0];
|
||||
clipped_tri[4] = intersect[1];
|
||||
clipped_tri[5] = intersect[2];
|
||||
|
||||
dist = Distance3D(nc[0], nc[1], nc[2], clipped_tri[3], clipped_tri[4], clipped_tri[5]);
|
||||
clipped_uv[2] = Interpolate(0, AB_dist, dist, nc_uv[0], pt_uv[0]);
|
||||
clipped_uv[3] = Interpolate(0, AB_dist, dist, nc_uv[1], pt_uv[1]);
|
||||
|
||||
//'AC
|
||||
lp[0] = pt[3];
|
||||
lp[1] = pt[4];
|
||||
lp[2] = pt[5];
|
||||
|
||||
ld[0] = nc[0] - lp[0];
|
||||
ld[1] = nc[1] - lp[1];
|
||||
ld[2] = nc[2] - lp[2];
|
||||
|
||||
GetLinePlaneIntersection(&lp[0], &ld[0], &p1[0], &p2[0], &p3[0], &intersect[0]);
|
||||
|
||||
clipped_tri[6] = intersect[0];
|
||||
clipped_tri[7] = intersect[1];
|
||||
clipped_tri[8] = intersect[2];
|
||||
|
||||
dist = Distance3D(nc[0], nc[1], nc[2], clipped_tri[6], clipped_tri[7], clipped_tri[8]);
|
||||
clipped_uv[4] = Interpolate(0, AC_dist, dist, nc_uv[0], pt_uv[2]);
|
||||
clipped_uv[5] = Interpolate(0, AC_dist, dist, nc_uv[1], pt_uv[3]);
|
||||
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void projectionGeometry(int cam_dist, int f_vertex_count, double* vertex3D, double* uv, double graph_offset_x, double graph_offset_y, uint32_t color,
|
||||
double* vertex_count, double* vertex2D, double* ind_count, double* index, double* clip_dist, double* min_x, double* min_y, double* max_x, double* max_y)
|
||||
{
|
||||
CAMERA_LENS = cam_dist;
|
||||
|
||||
if( f_vertex_count > 4 || f_vertex_count < 3)
|
||||
return;
|
||||
|
||||
int tri_index = 0;
|
||||
int uv_index = 0;
|
||||
|
||||
int clip = 0;
|
||||
|
||||
double clipped_tri[18], clipped_uv[12];
|
||||
double distance = 0;
|
||||
double cld = 0;
|
||||
int vi = 0;
|
||||
uint32_t r, g, b, a;
|
||||
r = ( (color >> 16) & 255);
|
||||
g = ( (color >> 8) & 255);
|
||||
b = ( color & 255);
|
||||
a = ( (color >> 24) & 255);
|
||||
|
||||
//cout << "color = " << color << ", " << r << ", " << g << ", " << b << ", " << a << endl;
|
||||
|
||||
int index_count = 0;
|
||||
vertex_count[0] = 0;
|
||||
|
||||
int ni = 0;
|
||||
|
||||
switch(f_vertex_count)
|
||||
{
|
||||
case 3:
|
||||
clip = ClipTriangle(&vertex3D[0], &uv[0], &clipped_tri[0], &clipped_uv[0]);
|
||||
if(clip > 0)
|
||||
{
|
||||
tri_index = 0;
|
||||
uv_index = 0;
|
||||
|
||||
for(int i = 0; i < clip; i++)
|
||||
{
|
||||
distance = CAMERA_LENS - clipped_tri[tri_index+2];
|
||||
distance = (distance <= 0) ? 1 : distance;
|
||||
cld = (CAMERA_LENS / distance);
|
||||
ni = vi * 8;
|
||||
vertex2D[ ni + 0 ] = (cld * clipped_tri[tri_index]) + graph_offset_x;
|
||||
vertex2D[ ni + 1 ] = graph_offset_y - (cld * clipped_tri[tri_index+1]);
|
||||
vertex2D[ ni + 2 ] = r;
|
||||
vertex2D[ ni + 3 ] = g;
|
||||
vertex2D[ ni + 4 ] = b;
|
||||
vertex2D[ ni + 5 ] = a;
|
||||
vertex2D[ ni + 6 ] = clipped_uv[uv_index]; //' uv_x + (uv_w * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 0]) 'u
|
||||
vertex2D[ ni + 7 ] = clipped_uv[uv_index+1]; //'uv_y + (uv_h * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 1]) 'v
|
||||
|
||||
clip_dist[0] = min(distance, clip_dist[0]);
|
||||
min_x[0] = min(vertex2D[ ni + 0], min_x[0]);
|
||||
min_y[0] = min(vertex2D[ ni + 1], min_y[0]);
|
||||
max_x[0] = max(vertex2D[ ni + 0], max_x[0]);
|
||||
max_y[0] = max(vertex2D[ ni + 1], max_y[0]);
|
||||
|
||||
index[index_count] = vi;
|
||||
index_count = index_count + 1;
|
||||
vi = vi + 1;
|
||||
tri_index = tri_index + 3;
|
||||
uv_index = uv_index + 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tri_index = 0;
|
||||
uv_index = 0;
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
distance = CAMERA_LENS - vertex3D[tri_index+2];
|
||||
distance = (distance<=0) ? 1 : distance;
|
||||
cld = (CAMERA_LENS / distance);
|
||||
ni = vi * 8;
|
||||
vertex2D[ ni + 0 ] = (cld * vertex3D[tri_index]) + graph_offset_x;
|
||||
vertex2D[ ni + 1 ] = graph_offset_y - (cld * vertex3D[tri_index+1]);
|
||||
vertex2D[ ni + 2 ] = r;
|
||||
vertex2D[ ni + 3 ] = g;
|
||||
vertex2D[ ni + 4 ] = b;
|
||||
vertex2D[ ni + 5 ] = a;
|
||||
vertex2D[ ni + 6 ] = uv[uv_index]; //' uv_x + (uv_w * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 0]) 'u
|
||||
vertex2D[ ni + 7 ] = uv[uv_index+1]; //'uv_y + (uv_h * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 1]) 'v
|
||||
|
||||
clip_dist[0] = min(distance, clip_dist[0]);
|
||||
min_x[0] = min(vertex2D[ ni + 0], min_x[0]);
|
||||
min_y[0] = min(vertex2D[ ni + 1], min_y[0]);
|
||||
max_x[0] = max(vertex2D[ ni + 0], max_x[0]);
|
||||
max_y[0] = max(vertex2D[ ni + 1], max_y[0]);
|
||||
|
||||
vi = vi + 1;
|
||||
tri_index = tri_index + 3;
|
||||
uv_index = uv_index + 2;
|
||||
}
|
||||
|
||||
index[index_count] = 0;
|
||||
index[index_count+1] = 1;
|
||||
index[index_count+2] = 2;
|
||||
index_count = index_count + 3;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
clip = ClipTriangle(&vertex3D[0], &uv[0], &clipped_tri[0], &clipped_uv[0]);
|
||||
if(clip > 0)
|
||||
{
|
||||
tri_index = 0;
|
||||
uv_index = 0;
|
||||
|
||||
for(int i = 0; i < clip; i++)
|
||||
{
|
||||
distance = CAMERA_LENS - clipped_tri[tri_index+2];
|
||||
distance = (distance<=0) ? 1 : distance;
|
||||
cld = (CAMERA_LENS / distance);
|
||||
ni = vi * 8;
|
||||
vertex2D[ ni + 0 ] = (cld * clipped_tri[tri_index]) + graph_offset_x;
|
||||
vertex2D[ ni + 1 ] = graph_offset_y - (cld * clipped_tri[tri_index+1]);
|
||||
vertex2D[ ni + 2 ] = r;
|
||||
vertex2D[ ni + 3 ] = g;
|
||||
vertex2D[ ni + 4 ] = b;
|
||||
vertex2D[ ni + 5 ] = a;
|
||||
vertex2D[ ni + 6 ] = clipped_uv[uv_index]; //' uv_x + (uv_w * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 0]) 'u
|
||||
vertex2D[ ni + 7 ] = clipped_uv[uv_index+1]; //'uv_y + (uv_h * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 1]) 'v
|
||||
|
||||
clip_dist[0] = min(distance, clip_dist[0]);
|
||||
min_x[0] = min(vertex2D[ ni + 0], min_x[0]);
|
||||
min_y[0] = min(vertex2D[ ni + 1], min_y[0]);
|
||||
max_x[0] = max(vertex2D[ ni + 0], max_x[0]);
|
||||
max_y[0] = max(vertex2D[ ni + 1], max_y[0]);
|
||||
|
||||
index[index_count] = vi;
|
||||
index_count = index_count + 1;
|
||||
vi = vi + 1;
|
||||
tri_index = tri_index + 3;
|
||||
uv_index = uv_index + 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//cout << "DBG: " << vertex3D[0] << ", " << vertex3D[1] << endl;
|
||||
tri_index = 0;
|
||||
uv_index = 0;
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
distance = CAMERA_LENS - vertex3D[tri_index+2];
|
||||
distance = (distance<=0) ? 1 : distance;
|
||||
cld = (CAMERA_LENS / distance);
|
||||
ni = vi * 8;
|
||||
vertex2D[ ni + 0 ] = (cld * vertex3D[tri_index]) + graph_offset_x;
|
||||
vertex2D[ ni + 1 ] = graph_offset_y - (cld * vertex3D[tri_index+1]);
|
||||
vertex2D[ ni + 2 ] = r;
|
||||
vertex2D[ ni + 3 ] = g;
|
||||
vertex2D[ ni + 4 ] = b;
|
||||
vertex2D[ ni + 5 ] = a;
|
||||
vertex2D[ ni + 6 ] = uv[uv_index]; //' uv_x + (uv_w * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 0]) 'u
|
||||
vertex2D[ ni + 7 ] = uv[uv_index+1]; //'uv_y + (uv_h * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 1]) 'v
|
||||
|
||||
clip_dist[0] = min(distance, clip_dist[0]);
|
||||
min_x[0] = min(vertex2D[ ni + 0], min_x[0]);
|
||||
min_y[0] = min(vertex2D[ ni + 1], min_y[0]);
|
||||
max_x[0] = max(vertex2D[ ni + 0], max_x[0]);
|
||||
max_y[0] = max(vertex2D[ ni + 1], max_y[0]);
|
||||
|
||||
vi = vi + 1;
|
||||
tri_index = tri_index + 3;
|
||||
uv_index = uv_index + 2;
|
||||
}
|
||||
|
||||
index[index_count] = 0;
|
||||
index[index_count+1] = 1;
|
||||
index[index_count+2] = 2;
|
||||
index_count = index_count + 3;
|
||||
}
|
||||
|
||||
vertex3D[3] = vertex3D[0];
|
||||
vertex3D[4] = vertex3D[1];
|
||||
vertex3D[5] = vertex3D[2];
|
||||
|
||||
uv[2] = uv[0];
|
||||
uv[3] = uv[1];
|
||||
clip = ClipTriangle(&vertex3D[3], &uv[2], &clipped_tri[0], &clipped_uv[0]);
|
||||
|
||||
if(clip > 0)
|
||||
{
|
||||
tri_index = 0;
|
||||
uv_index = 0;
|
||||
|
||||
for(int i = 0; i < clip; i++)
|
||||
{
|
||||
distance = CAMERA_LENS - clipped_tri[tri_index+2];
|
||||
distance = (distance<=0) ? 1 : distance;
|
||||
cld = (CAMERA_LENS / distance);
|
||||
ni = vi * 8;
|
||||
vertex2D[ ni + 0 ] = (cld * clipped_tri[tri_index]) + graph_offset_x;
|
||||
vertex2D[ ni + 1 ] = graph_offset_y - (cld * clipped_tri[tri_index+1]);
|
||||
vertex2D[ ni + 2 ] = r;
|
||||
vertex2D[ ni + 3 ] = g;
|
||||
vertex2D[ ni + 4 ] = b;
|
||||
vertex2D[ ni + 5 ] = a;
|
||||
vertex2D[ ni + 6 ] = clipped_uv[uv_index]; //' uv_x + (uv_w * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 0]) 'u
|
||||
vertex2D[ ni + 7 ] = clipped_uv[uv_index+1]; //'uv_y + (uv_h * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 1]) 'v
|
||||
|
||||
clip_dist[0] = min(distance, clip_dist[0]);
|
||||
min_x[0] = min(vertex2D[ ni + 0], min_x[0]);
|
||||
min_y[0] = min(vertex2D[ ni + 1], min_y[0]);
|
||||
max_x[0] = max(vertex2D[ ni + 0], max_x[0]);
|
||||
max_y[0] = max(vertex2D[ ni + 1], max_y[0]);
|
||||
|
||||
index[index_count] = vi;
|
||||
index_count = index_count + 1;
|
||||
|
||||
vi = vi + 1;
|
||||
|
||||
tri_index = tri_index + 3;
|
||||
uv_index = uv_index + 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tri_index = 3;
|
||||
uv_index = 2;
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
distance = CAMERA_LENS - vertex3D[tri_index+2];
|
||||
distance = (distance<=0) ? 1 : distance;
|
||||
cld = (CAMERA_LENS / distance);
|
||||
ni = vi * 8;
|
||||
vertex2D[ ni + 0 ] = (cld * vertex3D[tri_index]) + graph_offset_x;
|
||||
vertex2D[ ni + 1 ] = graph_offset_y - (cld * vertex3D[tri_index+1]);
|
||||
vertex2D[ ni + 2 ] = r;
|
||||
vertex2D[ ni + 3 ] = g;
|
||||
vertex2D[ ni + 4 ] = b;
|
||||
vertex2D[ ni + 5 ] = a;
|
||||
vertex2D[ ni + 6 ] = uv[uv_index]; //' uv_x + (uv_w * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 0]) 'u
|
||||
vertex2D[ ni + 7 ] = uv[uv_index+1]; //'uv_y + (uv_h * C3D_Mesh_TCoord[mesh, C3D_Mesh_Face_TCoord[mesh, face, i], 1]) 'v
|
||||
|
||||
clip_dist[0] = min(distance, clip_dist[0]);
|
||||
min_x[0] = min(vertex2D[ ni + 0], min_x[0]);
|
||||
min_y[0] = min(vertex2D[ ni + 1], min_y[0]);
|
||||
max_x[0] = max(vertex2D[ ni + 0], max_x[0]);
|
||||
max_y[0] = max(vertex2D[ ni + 1], max_y[0]);
|
||||
|
||||
index[index_count] = vi; //'They will already be in the right order here
|
||||
index_count = index_count + 1;
|
||||
vi = vi + 1;
|
||||
tri_index = tri_index + 3;
|
||||
uv_index = uv_index + 2;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
vertex_count[0] = (double)vi;
|
||||
ind_count[0] = (double)index_count;
|
||||
|
||||
//cout << "DEBUG: " << vertex_count[0] << ", " << ind_count[0] << endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void rc_GetProjectionGeometry(int cam_dist, uint32_t mA, int f_vertex_count, double* columns, double* uv, double graph_offset_x, double graph_offset_y, uint32_t color,
|
||||
double* vertex_count, double* vertex2D, double* ind_count, double* index, double* clip_dist, double* min_x, double* min_y, double* max_x, double* max_y)
|
||||
{
|
||||
double vertex3D[18]; // number of vertices * 3 -> ie. (x,y,z) for each vertex
|
||||
|
||||
int v_index = 0;
|
||||
for(int i = 0; i < f_vertex_count; i++)
|
||||
{
|
||||
vertex3D[v_index] = MatrixValue(mA, 0, columns[i]);
|
||||
vertex3D[v_index+1] = MatrixValue(mA, 1, columns[i]);
|
||||
vertex3D[v_index+2] = MatrixValue(mA, 2, columns[i]);
|
||||
v_index += 3;
|
||||
}
|
||||
|
||||
projectionGeometry(cam_dist, f_vertex_count, &vertex3D[0], uv, graph_offset_x, graph_offset_y, color,
|
||||
vertex_count, vertex2D, ind_count, index, clip_dist, min_x, min_y, max_x, max_y);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
|
||||
#endif // RC_GEOMETRY_H_INCLUDED
|
||||
1189
rcbasic_runtime/rc_matrix.h
Normal file
1189
rcbasic_runtime/rc_matrix.h
Normal file
File diff suppressed because it is too large
Load Diff
6502
rcbasic_runtime/rc_media.h
Normal file
6502
rcbasic_runtime/rc_media.h
Normal file
File diff suppressed because it is too large
Load Diff
23
rcbasic_runtime/rc_os_defines.h
Normal file
23
rcbasic_runtime/rc_os_defines.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef RC_OS_DEFINES_H_INCLUDED
|
||||
#define RC_OS_DEFINES_H_INCLUDED
|
||||
|
||||
#define RC_LINUX
|
||||
//#define RC_WEB
|
||||
//#define RC_WINDOWS
|
||||
//#define RC_ANDROID
|
||||
//#define RC_MAC
|
||||
//#define RC_IOS
|
||||
|
||||
#ifdef RC_WEB
|
||||
#define RC_LINUX
|
||||
#endif
|
||||
|
||||
#ifdef RC_ANDROID
|
||||
#define RC_MOBILE
|
||||
#endif
|
||||
|
||||
#ifdef RC_IOS
|
||||
#define RC_MOBILE
|
||||
#endif
|
||||
|
||||
#endif // RC_OS_DEFINES_H_INCLUDED
|
||||
555
rcbasic_runtime/rc_process.h
Normal file
555
rcbasic_runtime/rc_process.h
Normal file
@@ -0,0 +1,555 @@
|
||||
#ifndef RC_PROCESS_H_INCLUDED
|
||||
#define RC_PROCESS_H_INCLUDED
|
||||
|
||||
#include <iostream>
|
||||
#ifdef RC_ANDROID
|
||||
#include "SDL.h"
|
||||
#else
|
||||
#include <SDL2/SDL.h>
|
||||
#endif
|
||||
#include <queue>
|
||||
#include "rc_matrix.h"
|
||||
#include "rc_defines.h"
|
||||
|
||||
#define MAX_SUBPROCESS 3
|
||||
|
||||
#define RC_THREAD_ONERROR_CONTINUE 0
|
||||
#define RC_THREAD_ONERROR_STOP 1
|
||||
|
||||
SDL_Thread* rc_subprocess_thread[3];
|
||||
|
||||
struct rc_threadData
|
||||
{
|
||||
uint32_t sub_process_num;
|
||||
};
|
||||
|
||||
rc_threadData rc_subprocess_param[3];
|
||||
|
||||
struct rc_subprocess_mutex_container
|
||||
{
|
||||
SDL_mutex* queue_mutex;
|
||||
SDL_mutex* current_op_mutex;
|
||||
SDL_mutex* error_mode_mutex;
|
||||
bool queue_mutex_locked;
|
||||
bool current_op_mutex_locked;
|
||||
bool error_mode_mutex_locked;
|
||||
};
|
||||
|
||||
rc_subprocess_mutex_container rc_subprocess_mutex[3];
|
||||
|
||||
|
||||
struct rc_process_op
|
||||
{
|
||||
int fn;
|
||||
double n[10];
|
||||
// I will add a string arg whenever a string op gets implemented
|
||||
};
|
||||
|
||||
struct rc_process_op_list
|
||||
{
|
||||
queue<rc_process_op> op;
|
||||
};
|
||||
|
||||
rc_process_op_list rc_subprocess_queue[3];
|
||||
|
||||
uint32_t rc_subprocess_error_mode[3];
|
||||
int rc_subprocess_error[3];
|
||||
|
||||
int rc_active_matrix_process = -1;
|
||||
|
||||
void rc_initSubprocessSystem()
|
||||
{
|
||||
for(int i = 0; i < MAX_SUBPROCESS; i++)
|
||||
{
|
||||
rc_subprocess_thread[i] = NULL;
|
||||
rc_subprocess_mutex[i].current_op_mutex = SDL_CreateMutex();
|
||||
rc_subprocess_mutex[i].error_mode_mutex = SDL_CreateMutex();
|
||||
rc_subprocess_mutex[i].queue_mutex = SDL_CreateMutex();
|
||||
rc_subprocess_mutex[i].current_op_mutex_locked = false;
|
||||
rc_subprocess_mutex[i].error_mode_mutex_locked = false;
|
||||
rc_subprocess_mutex[i].queue_mutex_locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
#define RC_QUEUE_MUTEX 1
|
||||
#define RC_ERROR_MODE_MUTEX 2
|
||||
#define RC_CURRENT_OP_MUTEX 3
|
||||
|
||||
void rc_lockMutex(int process_num, uint32_t m)
|
||||
{
|
||||
switch(m)
|
||||
{
|
||||
case RC_QUEUE_MUTEX:
|
||||
if(!rc_subprocess_mutex[process_num].queue_mutex_locked)
|
||||
SDL_LockMutex(rc_subprocess_mutex[process_num].queue_mutex);
|
||||
rc_subprocess_mutex[process_num].queue_mutex_locked = true;
|
||||
break;
|
||||
|
||||
case RC_ERROR_MODE_MUTEX:
|
||||
if(!rc_subprocess_mutex[process_num].error_mode_mutex_locked)
|
||||
SDL_LockMutex(rc_subprocess_mutex[process_num].error_mode_mutex);
|
||||
rc_subprocess_mutex[process_num].error_mode_mutex_locked = true;
|
||||
break;
|
||||
|
||||
case RC_CURRENT_OP_MUTEX:
|
||||
if(!rc_subprocess_mutex[process_num].current_op_mutex_locked)
|
||||
SDL_LockMutex(rc_subprocess_mutex[process_num].current_op_mutex);
|
||||
rc_subprocess_mutex[process_num].current_op_mutex_locked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void rc_unlockMutex(int process_num, uint32_t m)
|
||||
{
|
||||
switch(m)
|
||||
{
|
||||
case RC_QUEUE_MUTEX:
|
||||
rc_subprocess_mutex[process_num].queue_mutex_locked = false;
|
||||
SDL_UnlockMutex(rc_subprocess_mutex[process_num].queue_mutex);
|
||||
break;
|
||||
|
||||
case RC_ERROR_MODE_MUTEX:
|
||||
rc_subprocess_mutex[process_num].error_mode_mutex_locked = false;
|
||||
SDL_UnlockMutex(rc_subprocess_mutex[process_num].error_mode_mutex);
|
||||
break;
|
||||
|
||||
case RC_CURRENT_OP_MUTEX:
|
||||
rc_subprocess_mutex[process_num].current_op_mutex_locked = false;
|
||||
SDL_UnlockMutex(rc_subprocess_mutex[process_num].current_op_mutex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int rc_subprocess_fn( void* data)
|
||||
{
|
||||
rc_threadData* param = (rc_threadData*) data;
|
||||
|
||||
int process_num = param->sub_process_num;
|
||||
|
||||
//std::cout << "thread start " << process_num << std::endl;
|
||||
|
||||
rc_process_op op;
|
||||
bool p_loop = true;
|
||||
|
||||
while(p_loop)
|
||||
{
|
||||
op.fn = -1;
|
||||
rc_lockMutex(process_num, RC_QUEUE_MUTEX);
|
||||
if(rc_subprocess_queue[process_num].op.size() > 0)
|
||||
{
|
||||
op = rc_subprocess_queue[process_num].op.front();
|
||||
rc_unlockMutex(process_num, RC_QUEUE_MUTEX);
|
||||
}
|
||||
else
|
||||
rc_unlockMutex(process_num, RC_QUEUE_MUTEX);
|
||||
|
||||
rc_lockMutex(process_num, RC_CURRENT_OP_MUTEX);
|
||||
rc_lockMutex(process_num, RC_ERROR_MODE_MUTEX);
|
||||
|
||||
switch(op.fn)
|
||||
{
|
||||
case 0:
|
||||
p_loop = false; //std::cout << "THREAD_END_OP " << std::endl;
|
||||
break;
|
||||
|
||||
case FN_DimMatrix: //Sub Procedure
|
||||
DimMatrix(op.n[0], op.n[1], op.n[2], op.n[3]);
|
||||
break;
|
||||
case FN_AddMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (AddMatrix(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_AugmentMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (AugmentMatrix(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_CopyMatrix: //Sub Procedure
|
||||
CopyMatrix(op.n[0], op.n[1]);
|
||||
break;
|
||||
case FN_InsertMatrixColumns: //Number Function
|
||||
rc_subprocess_error[process_num] = (InsertMatrixColumn(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_InsertMatrixRows: //Number Function
|
||||
rc_subprocess_error[process_num] = (InsertMatrixRow(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_MultiplyMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (MultiplyMatrix(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_CubeMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (CubeMatrix(op.n[0], op.n[1], process_num)) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_DeleteMatrixColumns: //Number Function
|
||||
rc_subprocess_error[process_num] = (DeleteMatrixColumns(op.n[0], op.n[1], op.n[2], process_num)) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_DeleteMatrixRows: //Number Function
|
||||
rc_subprocess_error[process_num] = (DeleteMatrixRows(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_ClearMatrix: //Sub Procedure
|
||||
ClearMatrix(op.n[0]);
|
||||
break;
|
||||
case FN_ClearMatrixColumns: //Number Function
|
||||
rc_subprocess_error[process_num] = (ClearMatrixColumns(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_ClearMatrixRows: //Number Function
|
||||
rc_subprocess_error[process_num] = (ClearMatrixRows(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_FillMatrix: //Sub Procedure
|
||||
FillMatrix(op.n[0], op.n[1]);
|
||||
break;
|
||||
case FN_FillMatrixColumns: //Number Function
|
||||
rc_subprocess_error[process_num] = (FillMatrixColumns(op.n[0], op.n[1], op.n[2], op.n[3])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_FillMatrixRows: //Number Function
|
||||
rc_subprocess_error[process_num] = (FillMatrixRows(op.n[0], op.n[1], op.n[2], op.n[3])) ? 0 : op.fn;
|
||||
break;
|
||||
case FN_CopyMatrixColumns: //Number Function
|
||||
rc_subprocess_error[process_num] = (GetMatrixColumns(op.n[0], op.n[1], op.n[2], op.n[3])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_CopyMatrixRows: //Number Function
|
||||
rc_subprocess_error[process_num] = (GetMatrixRows(op.n[0], op.n[1], op.n[2], op.n[3])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_IdentityMatrix: //Sub Procedure
|
||||
IdentityMatrix(op.n[0], op.n[1]);
|
||||
break;
|
||||
case FN_SolveMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (SolveMatrix(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_IsEqualMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (IsEqualMatrix(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_AdjointMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (AdjointMatrix(op.n[0], op.n[1])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_InvertMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (InvertMatrix(op.n[0], op.n[1])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_RandomizeMatrix: //Sub Procedure
|
||||
RandomizeMatrix(op.n[0], op.n[1], op.n[2]);
|
||||
break;
|
||||
case FN_SetMatrixValue: //Sub Procedure
|
||||
SetMatrixValue(op.n[0], op.n[1], op.n[2], op.n[3]);
|
||||
break;
|
||||
case FN_ScalarMatrix: //Sub Procedure
|
||||
ScalarMatrix(op.n[0], op.n[1], op.n[2]);
|
||||
break;
|
||||
case FN_ScalarMatrixColumns: //Number Function
|
||||
rc_subprocess_error[process_num] = (ScalarMatrixColumns(op.n[0], op.n[1], op.n[2], op.n[3], op.n[4])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_ScalarMatrixRows: //Number Function
|
||||
rc_subprocess_error[process_num] = (ScalarMatrixRows(op.n[0], op.n[1], op.n[2], op.n[3], op.n[4])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_SquareMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (SquareMatrix(op.n[0], op.n[1])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_SubMatrix: //Sub Procedure
|
||||
SubMatrix(op.n[0], op.n[1], op.n[2]);
|
||||
break;
|
||||
case FN_SubtractMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (SubtractMatrix(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_SwapMatrix: //Sub Procedure
|
||||
SwapMatrix(op.n[0], op.n[1], process_num); // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_SwapMatrixColumn: //Number Function
|
||||
rc_subprocess_error[process_num] = (SwapMatrixColumn(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_SwapMatrixRow: //Number Function
|
||||
rc_subprocess_error[process_num] = (SwapMatrixRow(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_TransposeMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (TransposeMatrix(op.n[0], op.n[1])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_UnAugmentMatrix: //Number Function
|
||||
rc_subprocess_error[process_num] = (UnAugmentMatrix(op.n[0], op.n[1], op.n[2])) ? 0 : op.fn; // 1 needs to be replaced with error code
|
||||
break;
|
||||
case FN_ZeroMatrix: //Sub Procedure
|
||||
ZeroMatrix(op.n[0]);
|
||||
break;
|
||||
case FN_ProcessSleep: //Sub Procedure
|
||||
SDL_Delay(op.n[0]);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if(op.fn >= 0)
|
||||
{
|
||||
rc_lockMutex(process_num, RC_QUEUE_MUTEX);
|
||||
if(rc_subprocess_queue[process_num].op.size()>0)
|
||||
rc_subprocess_queue[process_num].op.pop();
|
||||
rc_unlockMutex(process_num, RC_QUEUE_MUTEX);
|
||||
}
|
||||
|
||||
if(rc_subprocess_error[process_num] != 0)
|
||||
{
|
||||
switch(rc_subprocess_error_mode[process_num])
|
||||
{
|
||||
case RC_THREAD_ONERROR_CONTINUE:
|
||||
rc_unlockMutex(process_num, RC_ERROR_MODE_MUTEX);
|
||||
break;
|
||||
case RC_THREAD_ONERROR_STOP:
|
||||
rc_unlockMutex(process_num, RC_ERROR_MODE_MUTEX);
|
||||
bool error_status = true;
|
||||
while(error_status)
|
||||
{
|
||||
rc_lockMutex(process_num, RC_ERROR_MODE_MUTEX);
|
||||
error_status = (rc_subprocess_error[process_num] != 0);
|
||||
rc_unlockMutex(process_num, RC_ERROR_MODE_MUTEX);
|
||||
//std::cout << "THREAD_ERROR " << error_status << std::endl;
|
||||
SDL_Delay(5);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
rc_unlockMutex(process_num, RC_ERROR_MODE_MUTEX);
|
||||
|
||||
rc_unlockMutex(process_num, RC_CURRENT_OP_MUTEX);
|
||||
|
||||
}
|
||||
|
||||
//std::cout << "thread end " << process_num << std::endl;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool rc_setMatrixProcess(int p_num)
|
||||
{
|
||||
if(p_num >= 0 && p_num < MAX_SUBPROCESS)
|
||||
rc_active_matrix_process = p_num;
|
||||
else
|
||||
rc_active_matrix_process = -1;
|
||||
|
||||
if(rc_active_matrix_process >= 0)
|
||||
return (rc_subprocess_thread[rc_active_matrix_process] != NULL);
|
||||
|
||||
return true; //main process is set
|
||||
}
|
||||
|
||||
bool rc_processOpen(int p_num)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return false;
|
||||
|
||||
if(rc_subprocess_thread[p_num])
|
||||
return false;
|
||||
|
||||
for(int i = 0; i < rc_subprocess_queue[p_num].op.size(); i++)
|
||||
rc_subprocess_queue[p_num].op.pop();
|
||||
|
||||
rc_subprocess_thread[p_num] = SDL_CreateThread(rc_subprocess_fn, "rc_subprocess", &rc_subprocess_param[0]);
|
||||
|
||||
return (rc_subprocess_thread[p_num] != NULL);
|
||||
}
|
||||
|
||||
void rc_setProcessErrorMode(int p_num, uint32_t error_mode)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return;
|
||||
|
||||
if(error_mode < 0 || error_mode > 1)
|
||||
error_mode = 0;
|
||||
|
||||
rc_lockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
rc_subprocess_error_mode[p_num] = error_mode;
|
||||
rc_unlockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
}
|
||||
|
||||
int ProcessError(int p_num)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return 0;
|
||||
|
||||
rc_lockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
int error = rc_subprocess_error[p_num];
|
||||
rc_unlockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void ProcessWait(int p_num)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return;
|
||||
|
||||
if(!rc_subprocess_thread[p_num])
|
||||
return;
|
||||
|
||||
//std::cout << "q_LOCK " << std::endl;
|
||||
rc_lockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
uint32_t q_size = rc_subprocess_queue[p_num].op.size();
|
||||
rc_unlockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
|
||||
//std::cout << "q_size = " << q_size << std::endl;
|
||||
|
||||
while(q_size > 0)
|
||||
{
|
||||
rc_lockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
q_size = rc_subprocess_queue[p_num].op.size();
|
||||
rc_unlockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ProcessWaitAll()
|
||||
{
|
||||
for(uint32_t i = 0; i < MAX_SUBPROCESS; i++)
|
||||
ProcessWait(i);
|
||||
}
|
||||
|
||||
void ProcessContinue(int p_num)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return;
|
||||
|
||||
rc_lockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
rc_subprocess_error[p_num] = 0;
|
||||
rc_unlockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
|
||||
rc_unlockMutex(p_num, RC_CURRENT_OP_MUTEX);
|
||||
}
|
||||
|
||||
void ProcessContinueAll()
|
||||
{
|
||||
for(uint32_t i = 0; i < MAX_SUBPROCESS; i++)
|
||||
ProcessContinue(i);
|
||||
}
|
||||
|
||||
void ProcessStop(int p_num)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return;
|
||||
|
||||
rc_lockMutex(p_num, RC_CURRENT_OP_MUTEX);
|
||||
}
|
||||
|
||||
void ProcessStopAll()
|
||||
{
|
||||
for(uint32_t i = 0; i < MAX_SUBPROCESS; i++)
|
||||
ProcessStop(i);
|
||||
}
|
||||
|
||||
void ProcessClear(int p_num)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return;
|
||||
|
||||
rc_lockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
uint32_t q_size = rc_subprocess_queue[p_num].op.size();
|
||||
|
||||
for(uint32_t i = 0; i < q_size; i++)
|
||||
rc_subprocess_queue[p_num].op.pop();
|
||||
|
||||
rc_unlockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
|
||||
rc_lockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
rc_subprocess_error[p_num] = 0;
|
||||
rc_unlockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
}
|
||||
|
||||
bool ProcessClose(int p_num)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return false;
|
||||
|
||||
if(!rc_subprocess_thread[p_num])
|
||||
return false;
|
||||
|
||||
rc_process_op op;
|
||||
op.fn = 0;
|
||||
|
||||
ProcessClear(p_num);
|
||||
|
||||
rc_lockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
rc_subprocess_queue[p_num].op.push(op);
|
||||
rc_unlockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
|
||||
SDL_WaitThread(rc_subprocess_thread[p_num], NULL);
|
||||
|
||||
rc_subprocess_thread[p_num] = NULL;
|
||||
|
||||
if(rc_active_matrix_process == p_num)
|
||||
rc_active_matrix_process = -1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t ProcessErrorMode(int p_num)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return 0;
|
||||
|
||||
rc_lockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
uint32_t error_mode = rc_subprocess_error_mode[p_num];
|
||||
rc_unlockMutex(p_num, RC_ERROR_MODE_MUTEX);
|
||||
return error_mode;
|
||||
}
|
||||
|
||||
void ProcessSleep(int p_num, uint32_t msec)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return;
|
||||
|
||||
rc_process_op op;
|
||||
op.fn = FN_ProcessSleep;
|
||||
op.n[0] = msec;
|
||||
|
||||
rc_lockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
rc_subprocess_queue[p_num].op.push(op);
|
||||
rc_unlockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
}
|
||||
|
||||
bool ProcessExists(int p_num)
|
||||
{
|
||||
if(p_num < 0 || p_num >= MAX_SUBPROCESS)
|
||||
return false;
|
||||
|
||||
return (rc_subprocess_thread[p_num] != NULL);
|
||||
}
|
||||
|
||||
uint32_t ProcessQueueSize(int p_num)
|
||||
{
|
||||
rc_lockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
int q_size = rc_subprocess_queue[p_num].op.size();
|
||||
rc_unlockMutex(p_num, RC_QUEUE_MUTEX);
|
||||
|
||||
return q_size;
|
||||
}
|
||||
|
||||
void ProcessQueueMatrixOp(uint32_t fn, double n0 = 0, double n1 = 0, double n2 = 0, double n3 = 0, double n4 = 0, double n5 = 0,
|
||||
double n6 = 0, double n7 = 0, double n8 = 0, double n9 = 0)
|
||||
{
|
||||
rc_process_op op;
|
||||
op.fn = fn;
|
||||
op.n[0] = n0;
|
||||
op.n[1] = n1;
|
||||
op.n[2] = n2;
|
||||
op.n[3] = n3;
|
||||
op.n[4] = n4;
|
||||
op.n[5] = n5;
|
||||
op.n[6] = n6;
|
||||
op.n[7] = n7;
|
||||
op.n[8] = n8;
|
||||
op.n[9] = n9;
|
||||
|
||||
rc_lockMutex(rc_active_matrix_process, RC_QUEUE_MUTEX);
|
||||
rc_subprocess_queue[rc_active_matrix_process].op.push(op);
|
||||
rc_unlockMutex(rc_active_matrix_process, RC_QUEUE_MUTEX);
|
||||
}
|
||||
|
||||
void rc_cleanSubprocessSystem()
|
||||
{
|
||||
for(int i = 0; i < MAX_SUBPROCESS; i++)
|
||||
{
|
||||
ProcessClose(i);
|
||||
SDL_DestroyMutex(rc_subprocess_mutex[i].current_op_mutex);
|
||||
SDL_DestroyMutex(rc_subprocess_mutex[i].error_mode_mutex);
|
||||
SDL_DestroyMutex(rc_subprocess_mutex[i].queue_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
int NumCPUs()
|
||||
{
|
||||
return SDL_GetCPUCount();
|
||||
}
|
||||
|
||||
#endif // RC_PROCESS_H_INCLUDED
|
||||
1556
rcbasic_runtime/rc_stdlib.h
Normal file
1556
rcbasic_runtime/rc_stdlib.h
Normal file
File diff suppressed because it is too large
Load Diff
1
rcbasic_runtime/resource.rc
Normal file
1
rcbasic_runtime/resource.rc
Normal file
@@ -0,0 +1 @@
|
||||
MAINICON ICON "rcbasic.ico"
|
||||
820
rcbasic_runtime/theoraplay.c
Normal file
820
rcbasic_runtime/theoraplay.c
Normal file
@@ -0,0 +1,820 @@
|
||||
/**
|
||||
* TheoraPlay; multithreaded Ogg Theora/Ogg Vorbis decoding.
|
||||
*
|
||||
* Please see the file LICENSE.txt in the source's root directory.
|
||||
*
|
||||
* This file written by Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
// I wrote this with a lot of peeking at the Theora example code in
|
||||
// libtheora-1.1.1/examples/player_example.c, but this is all my own
|
||||
// code.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "SDL2/SDL.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#define THEORAPLAY_THREAD_T HANDLE
|
||||
#define THEORAPLAY_MUTEX_T HANDLE
|
||||
#define sleepms(x) Sleep(x)
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#define sleepms(x) usleep((x) * 1000)
|
||||
#define THEORAPLAY_THREAD_T pthread_t
|
||||
#define THEORAPLAY_MUTEX_T pthread_mutex_t
|
||||
#endif
|
||||
|
||||
#include "theoraplay.h"
|
||||
#include "theora/theoradec.h"
|
||||
#include "vorbis/codec.h"
|
||||
|
||||
#define THEORAPLAY_INTERNAL 1
|
||||
|
||||
typedef THEORAPLAY_VideoFrame VideoFrame;
|
||||
typedef THEORAPLAY_AudioPacket AudioPacket;
|
||||
|
||||
// !!! FIXME: these all count on the pixel format being TH_PF_420 for now.
|
||||
|
||||
typedef unsigned char *(*ConvertVideoFrameFn)(const th_info *tinfo,
|
||||
const th_ycbcr_buffer ycbcr);
|
||||
|
||||
static unsigned char *ConvertVideoFrame420ToYUVPlanar(
|
||||
const th_info *tinfo, const th_ycbcr_buffer ycbcr,
|
||||
const int p0, const int p1, const int p2)
|
||||
{
|
||||
int i;
|
||||
const int w = tinfo->pic_width;
|
||||
const int h = tinfo->pic_height;
|
||||
const int yoff = (tinfo->pic_x & ~1) + ycbcr[0].stride * (tinfo->pic_y & ~1);
|
||||
const int uvoff = (tinfo->pic_x / 2) + (ycbcr[1].stride) * (tinfo->pic_y / 2);
|
||||
unsigned char *yuv = (unsigned char *) malloc(w * h * 2);
|
||||
if (yuv)
|
||||
{
|
||||
unsigned char *dst = yuv;
|
||||
for (i = 0; i < h; i++, dst += w)
|
||||
memcpy(dst, ycbcr[p0].data + yoff + ycbcr[p0].stride * i, w);
|
||||
for (i = 0; i < (h / 2); i++, dst += w/2)
|
||||
memcpy(dst, ycbcr[p1].data + uvoff + ycbcr[p1].stride * i, w / 2);
|
||||
for (i = 0; i < (h / 2); i++, dst += w/2)
|
||||
memcpy(dst, ycbcr[p2].data + uvoff + ycbcr[p2].stride * i, w / 2);
|
||||
} // if
|
||||
|
||||
return yuv;
|
||||
} // ConvertVideoFrame420ToYUVPlanar
|
||||
|
||||
|
||||
static unsigned char *ConvertVideoFrame420ToYV12(const th_info *tinfo,
|
||||
const th_ycbcr_buffer ycbcr)
|
||||
{
|
||||
return ConvertVideoFrame420ToYUVPlanar(tinfo, ycbcr, 0, 2, 1);
|
||||
} // ConvertVideoFrame420ToYV12
|
||||
|
||||
|
||||
static unsigned char *ConvertVideoFrame420ToIYUV(const th_info *tinfo,
|
||||
const th_ycbcr_buffer ycbcr)
|
||||
{
|
||||
return ConvertVideoFrame420ToYUVPlanar(tinfo, ycbcr, 0, 1, 2);
|
||||
} // ConvertVideoFrame420ToIYUV
|
||||
|
||||
|
||||
// RGB
|
||||
#define THEORAPLAY_CVT_FNNAME_420 ConvertVideoFrame420ToRGB
|
||||
#define THEORAPLAY_CVT_RGB_ALPHA 0
|
||||
#include "theoraplay_cvtrgb.h"
|
||||
#undef THEORAPLAY_CVT_RGB_ALPHA
|
||||
#undef THEORAPLAY_CVT_FNNAME_420
|
||||
|
||||
// RGBA
|
||||
#define THEORAPLAY_CVT_FNNAME_420 ConvertVideoFrame420ToRGBA
|
||||
#define THEORAPLAY_CVT_RGB_ALPHA 1
|
||||
#include "theoraplay_cvtrgb.h"
|
||||
#undef THEORAPLAY_CVT_RGB_ALPHA
|
||||
#undef THEORAPLAY_CVT_FNNAME_420
|
||||
|
||||
|
||||
typedef struct TheoraDecoder
|
||||
{
|
||||
// Thread wrangling...
|
||||
int thread_created;
|
||||
THEORAPLAY_MUTEX_T lock;
|
||||
volatile int halt;
|
||||
int thread_done;
|
||||
THEORAPLAY_THREAD_T worker;
|
||||
|
||||
// API state...
|
||||
THEORAPLAY_Io *io;
|
||||
unsigned int maxframes; // Max video frames to buffer.
|
||||
volatile unsigned int prepped;
|
||||
volatile unsigned int videocount; // currently buffered frames.
|
||||
volatile unsigned int audioms; // currently buffered audio samples.
|
||||
volatile int hasvideo;
|
||||
volatile int hasaudio;
|
||||
volatile int decode_error;
|
||||
|
||||
THEORAPLAY_VideoFormat vidfmt;
|
||||
ConvertVideoFrameFn vidcvt;
|
||||
|
||||
VideoFrame *videolist;
|
||||
VideoFrame *videolisttail;
|
||||
|
||||
AudioPacket *audiolist;
|
||||
AudioPacket *audiolisttail;
|
||||
} TheoraDecoder;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
static inline int Thread_Create(TheoraDecoder *ctx, void *(*routine) (void*))
|
||||
{
|
||||
ctx->worker = CreateThread(
|
||||
NULL,
|
||||
0,
|
||||
(LPTHREAD_START_ROUTINE) routine,
|
||||
(LPVOID) ctx,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
return (ctx->worker == NULL);
|
||||
}
|
||||
static inline void Thread_Join(THEORAPLAY_THREAD_T thread)
|
||||
{
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
CloseHandle(thread);
|
||||
}
|
||||
static inline int Mutex_Create(TheoraDecoder *ctx)
|
||||
{
|
||||
ctx->lock = CreateMutex(NULL, FALSE, NULL);
|
||||
return (ctx->lock == NULL);
|
||||
}
|
||||
static inline void Mutex_Destroy(THEORAPLAY_MUTEX_T mutex)
|
||||
{
|
||||
CloseHandle(mutex);
|
||||
}
|
||||
static inline void Mutex_Lock(THEORAPLAY_MUTEX_T mutex)
|
||||
{
|
||||
WaitForSingleObject(mutex, INFINITE);
|
||||
}
|
||||
static inline void Mutex_Unlock(THEORAPLAY_MUTEX_T mutex)
|
||||
{
|
||||
ReleaseMutex(mutex);
|
||||
}
|
||||
#else
|
||||
static inline int Thread_Create(TheoraDecoder *ctx, void *(*routine) (void*))
|
||||
{
|
||||
return pthread_create(&ctx->worker, NULL, routine, ctx);
|
||||
}
|
||||
static inline void Thread_Join(THEORAPLAY_THREAD_T thread)
|
||||
{
|
||||
pthread_join(thread, NULL);
|
||||
}
|
||||
static inline int Mutex_Create(TheoraDecoder *ctx)
|
||||
{
|
||||
return pthread_mutex_init(&ctx->lock, NULL);
|
||||
}
|
||||
static inline void Mutex_Destroy(THEORAPLAY_MUTEX_T mutex)
|
||||
{
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
static inline void Mutex_Lock(THEORAPLAY_MUTEX_T mutex)
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
}
|
||||
static inline void Mutex_Unlock(THEORAPLAY_MUTEX_T mutex)
|
||||
{
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int FeedMoreOggData(THEORAPLAY_Io *io, ogg_sync_state *sync)
|
||||
{
|
||||
long buflen = 4096;
|
||||
char *buffer = ogg_sync_buffer(sync, buflen);
|
||||
if (buffer == NULL)
|
||||
return -1;
|
||||
|
||||
buflen = io->read(io, buffer, buflen);
|
||||
if (buflen <= 0)
|
||||
return 0;
|
||||
|
||||
return (ogg_sync_wrote(sync, buflen) == 0) ? 1 : -1;
|
||||
} // FeedMoreOggData
|
||||
|
||||
|
||||
// This massive function is where all the effort happens.
|
||||
static void WorkerThread(TheoraDecoder *ctx)
|
||||
{
|
||||
// make sure we initialized the stream before using pagein, but the stream
|
||||
// will know to ignore pages that aren't meant for it, so pass to both.
|
||||
#define queue_ogg_page(ctx) do { \
|
||||
if (tpackets) ogg_stream_pagein(&tstream, &page); \
|
||||
if (vpackets) ogg_stream_pagein(&vstream, &page); \
|
||||
} while (0)
|
||||
|
||||
unsigned long audioframes = 0;
|
||||
unsigned long videoframes = 0;
|
||||
double fps = 0.0;
|
||||
int was_error = 1; // resets to 0 at the end.
|
||||
int eos = 0; // end of stream flag.
|
||||
|
||||
// Too much Ogg/Vorbis/Theora state...
|
||||
ogg_packet packet;
|
||||
ogg_sync_state sync;
|
||||
ogg_page page;
|
||||
int vpackets = 0;
|
||||
vorbis_info vinfo;
|
||||
vorbis_comment vcomment;
|
||||
ogg_stream_state vstream;
|
||||
int vdsp_init = 0;
|
||||
vorbis_dsp_state vdsp;
|
||||
int tpackets = 0;
|
||||
th_info tinfo;
|
||||
th_comment tcomment;
|
||||
ogg_stream_state tstream;
|
||||
int vblock_init = 0;
|
||||
vorbis_block vblock;
|
||||
th_dec_ctx *tdec = NULL;
|
||||
th_setup_info *tsetup = NULL;
|
||||
|
||||
ogg_sync_init(&sync);
|
||||
vorbis_info_init(&vinfo);
|
||||
vorbis_comment_init(&vcomment);
|
||||
th_comment_init(&tcomment);
|
||||
th_info_init(&tinfo);
|
||||
|
||||
int bos = 1;
|
||||
while (!ctx->halt && bos)
|
||||
{
|
||||
if (FeedMoreOggData(ctx->io, &sync) <= 0)
|
||||
goto cleanup;
|
||||
|
||||
// parse out the initial header.
|
||||
while ( (!ctx->halt) && (ogg_sync_pageout(&sync, &page) > 0) )
|
||||
{
|
||||
ogg_stream_state test;
|
||||
|
||||
if (!ogg_page_bos(&page)) // not a header.
|
||||
{
|
||||
queue_ogg_page(ctx);
|
||||
bos = 0;
|
||||
break;
|
||||
} // if
|
||||
|
||||
ogg_stream_init(&test, ogg_page_serialno(&page));
|
||||
ogg_stream_pagein(&test, &page);
|
||||
ogg_stream_packetout(&test, &packet);
|
||||
|
||||
if (!tpackets && (th_decode_headerin(&tinfo, &tcomment, &tsetup, &packet) >= 0))
|
||||
{
|
||||
memcpy(&tstream, &test, sizeof (test));
|
||||
tpackets = 1;
|
||||
} // if
|
||||
else if (!vpackets && (vorbis_synthesis_headerin(&vinfo, &vcomment, &packet) >= 0))
|
||||
{
|
||||
memcpy(&vstream, &test, sizeof (test));
|
||||
vpackets = 1;
|
||||
} // else if
|
||||
else
|
||||
{
|
||||
// whatever it is, we don't care about it
|
||||
ogg_stream_clear(&test);
|
||||
} // else
|
||||
} // while
|
||||
} // while
|
||||
|
||||
// no audio OR video?
|
||||
if (ctx->halt || (!vpackets && !tpackets))
|
||||
goto cleanup;
|
||||
|
||||
// apparently there are two more theora and two more vorbis headers next.
|
||||
while ((!ctx->halt) && ((tpackets && (tpackets < 3)) || (vpackets && (vpackets < 3))))
|
||||
{
|
||||
while (!ctx->halt && tpackets && (tpackets < 3))
|
||||
{
|
||||
if (ogg_stream_packetout(&tstream, &packet) != 1)
|
||||
break; // get more data?
|
||||
if (!th_decode_headerin(&tinfo, &tcomment, &tsetup, &packet))
|
||||
goto cleanup;
|
||||
tpackets++;
|
||||
} // while
|
||||
|
||||
while (!ctx->halt && vpackets && (vpackets < 3))
|
||||
{
|
||||
if (ogg_stream_packetout(&vstream, &packet) != 1)
|
||||
break; // get more data?
|
||||
if (vorbis_synthesis_headerin(&vinfo, &vcomment, &packet))
|
||||
goto cleanup;
|
||||
vpackets++;
|
||||
} // while
|
||||
|
||||
// get another page, try again?
|
||||
if (ogg_sync_pageout(&sync, &page) > 0)
|
||||
queue_ogg_page(ctx);
|
||||
else if (FeedMoreOggData(ctx->io, &sync) <= 0)
|
||||
goto cleanup;
|
||||
} // while
|
||||
|
||||
// okay, now we have our streams, ready to set up decoding.
|
||||
if (!ctx->halt && tpackets)
|
||||
{
|
||||
// th_decode_alloc() docs say to check for insanely large frames yourself.
|
||||
if ((tinfo.frame_width > 99999) || (tinfo.frame_height > 99999))
|
||||
goto cleanup;
|
||||
|
||||
// We treat "unspecified" as NTSC. *shrug*
|
||||
if ( (tinfo.colorspace != TH_CS_UNSPECIFIED) &&
|
||||
(tinfo.colorspace != TH_CS_ITU_REC_470M) &&
|
||||
(tinfo.colorspace != TH_CS_ITU_REC_470BG) )
|
||||
{
|
||||
assert(0 && "Unsupported colorspace."); // !!! FIXME
|
||||
goto cleanup;
|
||||
} // if
|
||||
|
||||
if (tinfo.pixel_fmt != TH_PF_420) { assert(0); goto cleanup; } // !!! FIXME
|
||||
|
||||
if (tinfo.fps_denominator != 0)
|
||||
fps = ((double) tinfo.fps_numerator) / ((double) tinfo.fps_denominator);
|
||||
|
||||
tdec = th_decode_alloc(&tinfo, tsetup);
|
||||
if (!tdec) goto cleanup;
|
||||
|
||||
// Set decoder to maximum post-processing level.
|
||||
// Theoretically we could try dropping this level if we're not keeping up.
|
||||
int pp_level_max = 0;
|
||||
// !!! FIXME: maybe an API to set this?
|
||||
//th_decode_ctl(tdec, TH_DECCTL_GET_PPLEVEL_MAX, &pp_level_max, sizeof(pp_level_max));
|
||||
th_decode_ctl(tdec, TH_DECCTL_SET_PPLEVEL, &pp_level_max, sizeof(pp_level_max));
|
||||
} // if
|
||||
|
||||
// Done with this now.
|
||||
if (tsetup != NULL)
|
||||
{
|
||||
th_setup_free(tsetup);
|
||||
tsetup = NULL;
|
||||
} // if
|
||||
|
||||
if (!ctx->halt && vpackets)
|
||||
{
|
||||
vdsp_init = (vorbis_synthesis_init(&vdsp, &vinfo) == 0);
|
||||
if (!vdsp_init)
|
||||
goto cleanup;
|
||||
vblock_init = (vorbis_block_init(&vdsp, &vblock) == 0);
|
||||
if (!vblock_init)
|
||||
goto cleanup;
|
||||
} // if
|
||||
|
||||
// Now we can start the actual decoding!
|
||||
// Note that audio and video don't _HAVE_ to start simultaneously.
|
||||
|
||||
Mutex_Lock(ctx->lock);
|
||||
ctx->prepped = 1;
|
||||
ctx->hasvideo = (tpackets != 0);
|
||||
ctx->hasaudio = (vpackets != 0);
|
||||
Mutex_Unlock(ctx->lock);
|
||||
|
||||
while (!ctx->halt && !eos)
|
||||
{
|
||||
int need_pages = 0; // need more Ogg pages?
|
||||
int saw_video_frame = 0;
|
||||
|
||||
// Try to read as much audio as we can at once. We limit the outer
|
||||
// loop to one video frame and as much audio as we can eat.
|
||||
while (!ctx->halt && vpackets)
|
||||
{
|
||||
float **pcm = NULL;
|
||||
const int frames = vorbis_synthesis_pcmout(&vdsp, &pcm);
|
||||
if (frames > 0)
|
||||
{
|
||||
const int channels = vinfo.channels;
|
||||
int chanidx, frameidx;
|
||||
float *samples;
|
||||
AudioPacket *item = (AudioPacket *) malloc(sizeof (AudioPacket));
|
||||
if (item == NULL) goto cleanup;
|
||||
item->playms = (unsigned long) ((((double) audioframes) / ((double) vinfo.rate)) * 1000.0);
|
||||
item->channels = channels;
|
||||
item->freq = vinfo.rate;
|
||||
item->frames = frames;
|
||||
item->samples = (float *) malloc(sizeof (float) * frames * channels);
|
||||
item->next = NULL;
|
||||
|
||||
if (item->samples == NULL)
|
||||
{
|
||||
free(item);
|
||||
goto cleanup;
|
||||
} // if
|
||||
|
||||
// I bet this beats the crap out of the CPU cache...
|
||||
samples = item->samples;
|
||||
for (frameidx = 0; frameidx < frames; frameidx++)
|
||||
{
|
||||
for (chanidx = 0; chanidx < channels; chanidx++)
|
||||
*(samples++) = pcm[chanidx][frameidx];
|
||||
} // for
|
||||
|
||||
vorbis_synthesis_read(&vdsp, frames); // we ate everything.
|
||||
audioframes += frames;
|
||||
|
||||
//printf("Decoded %d frames of audio.\n", (int) frames);
|
||||
Mutex_Lock(ctx->lock);
|
||||
ctx->audioms += item->playms;
|
||||
if (ctx->audiolisttail)
|
||||
{
|
||||
assert(ctx->audiolist);
|
||||
ctx->audiolisttail->next = item;
|
||||
} // if
|
||||
else
|
||||
{
|
||||
assert(!ctx->audiolist);
|
||||
ctx->audiolist = item;
|
||||
} // else
|
||||
ctx->audiolisttail = item;
|
||||
Mutex_Unlock(ctx->lock);
|
||||
} // if
|
||||
|
||||
else // no audio available left in current packet?
|
||||
{
|
||||
// try to feed another packet to the Vorbis stream...
|
||||
if (ogg_stream_packetout(&vstream, &packet) <= 0)
|
||||
{
|
||||
if (!tpackets)
|
||||
need_pages = 1; // no video, get more pages now.
|
||||
break; // we'll get more pages when the video catches up.
|
||||
} // if
|
||||
else
|
||||
{
|
||||
if (vorbis_synthesis(&vblock, &packet) == 0)
|
||||
vorbis_synthesis_blockin(&vdsp, &vblock);
|
||||
} // else
|
||||
} // else
|
||||
} // while
|
||||
|
||||
if (!ctx->halt && tpackets)
|
||||
{
|
||||
// Theora, according to example_player.c, is
|
||||
// "one [packet] in, one [frame] out."
|
||||
if (ogg_stream_packetout(&tstream, &packet) <= 0)
|
||||
need_pages = 1;
|
||||
else
|
||||
{
|
||||
ogg_int64_t granulepos = 0;
|
||||
const int rc = th_decode_packetin(tdec, &packet, &granulepos);
|
||||
if (rc == TH_DUPFRAME)
|
||||
videoframes++; // nothing else to do.
|
||||
else if (rc == 0) // new frame!
|
||||
{
|
||||
th_ycbcr_buffer ycbcr;
|
||||
if (th_decode_ycbcr_out(tdec, ycbcr) == 0)
|
||||
{
|
||||
VideoFrame *item = (VideoFrame *) malloc(sizeof (VideoFrame));
|
||||
if (item == NULL) goto cleanup;
|
||||
item->playms = (fps == 0) ? 0 : (unsigned int) ((((double) videoframes) / fps) * 1000.0);
|
||||
item->fps = fps;
|
||||
item->width = tinfo.pic_width;
|
||||
item->height = tinfo.pic_height;
|
||||
item->format = ctx->vidfmt;
|
||||
item->pixels = ctx->vidcvt(&tinfo, ycbcr);
|
||||
item->next = NULL;
|
||||
|
||||
if (item->pixels == NULL)
|
||||
{
|
||||
free(item);
|
||||
goto cleanup;
|
||||
} // if
|
||||
|
||||
//printf("Decoded another video frame.\n");
|
||||
Mutex_Lock(ctx->lock);
|
||||
if (ctx->videolisttail)
|
||||
{
|
||||
assert(ctx->videolist);
|
||||
ctx->videolisttail->next = item;
|
||||
} // if
|
||||
else
|
||||
{
|
||||
assert(!ctx->videolist);
|
||||
ctx->videolist = item;
|
||||
} // else
|
||||
ctx->videolisttail = item;
|
||||
ctx->videocount++;
|
||||
Mutex_Unlock(ctx->lock);
|
||||
|
||||
saw_video_frame = 1;
|
||||
} // if
|
||||
videoframes++;
|
||||
} // if
|
||||
} // else
|
||||
} // if
|
||||
|
||||
if (!ctx->halt && need_pages)
|
||||
{
|
||||
const int rc = FeedMoreOggData(ctx->io, &sync);
|
||||
if (rc == 0)
|
||||
eos = 1; // end of stream
|
||||
else if (rc < 0)
|
||||
goto cleanup; // i/o error, etc.
|
||||
else
|
||||
{
|
||||
while (!ctx->halt && (ogg_sync_pageout(&sync, &page) > 0))
|
||||
queue_ogg_page(ctx);
|
||||
} // else
|
||||
} // if
|
||||
|
||||
// Sleep the process until we have space for more frames.
|
||||
if (saw_video_frame)
|
||||
{
|
||||
int go_on = !ctx->halt;
|
||||
//printf("Sleeping.\n");
|
||||
while (go_on)
|
||||
{
|
||||
// !!! FIXME: This is stupid. I should use a semaphore for this.
|
||||
Mutex_Lock(ctx->lock);
|
||||
go_on = !ctx->halt && (ctx->videocount >= ctx->maxframes);
|
||||
Mutex_Unlock(ctx->lock);
|
||||
if (go_on)
|
||||
sleepms(10);
|
||||
} // while
|
||||
//printf("Awake!\n");
|
||||
} // if
|
||||
} // while
|
||||
|
||||
was_error = 0;
|
||||
|
||||
cleanup:
|
||||
ctx->decode_error = (!ctx->halt && was_error);
|
||||
if (tdec != NULL) th_decode_free(tdec);
|
||||
if (tsetup != NULL) th_setup_free(tsetup);
|
||||
if (vblock_init) vorbis_block_clear(&vblock);
|
||||
if (vdsp_init) vorbis_dsp_clear(&vdsp);
|
||||
if (tpackets) ogg_stream_clear(&tstream);
|
||||
if (vpackets) ogg_stream_clear(&vstream);
|
||||
th_info_clear(&tinfo);
|
||||
th_comment_clear(&tcomment);
|
||||
vorbis_comment_clear(&vcomment);
|
||||
vorbis_info_clear(&vinfo);
|
||||
ogg_sync_clear(&sync);
|
||||
ctx->io->close(ctx->io);
|
||||
ctx->thread_done = 1;
|
||||
} // WorkerThread
|
||||
|
||||
|
||||
static void *WorkerThreadEntry(void *_this)
|
||||
{
|
||||
TheoraDecoder *ctx = (TheoraDecoder *) _this;
|
||||
WorkerThread(ctx);
|
||||
//printf("Worker thread is done.\n");
|
||||
return NULL;
|
||||
} // WorkerThreadEntry
|
||||
|
||||
|
||||
static long IoFopenRead(THEORAPLAY_Io *io, void *buf, long buflen)
|
||||
{
|
||||
SDL_RWops *f = (SDL_RWops *) io->userdata;
|
||||
const size_t br = SDL_RWread(f, buf, 1, buflen);
|
||||
if (br == 0)
|
||||
return -1;
|
||||
return (long) br;
|
||||
} // IoFopenRead
|
||||
|
||||
|
||||
static void IoFopenClose(THEORAPLAY_Io *io)
|
||||
{
|
||||
SDL_RWops *f = (SDL_RWops *) io->userdata;
|
||||
SDL_RWclose(f);
|
||||
free(io);
|
||||
} // IoFopenClose
|
||||
|
||||
|
||||
THEORAPLAY_Decoder *THEORAPLAY_startDecodeFile(const char *fname,
|
||||
const unsigned int maxframes,
|
||||
THEORAPLAY_VideoFormat vidfmt)
|
||||
{
|
||||
THEORAPLAY_Io *io = (THEORAPLAY_Io *) malloc(sizeof (THEORAPLAY_Io));
|
||||
if (io == NULL)
|
||||
return NULL;
|
||||
|
||||
SDL_RWops *f = SDL_RWFromFile(fname, "rb");
|
||||
if (f == NULL)
|
||||
{
|
||||
free(io);
|
||||
return NULL;
|
||||
} // if
|
||||
|
||||
io->read = IoFopenRead;
|
||||
io->close = IoFopenClose;
|
||||
io->userdata = f;
|
||||
return THEORAPLAY_startDecode(io, maxframes, vidfmt);
|
||||
} // THEORAPLAY_startDecodeFile
|
||||
|
||||
|
||||
THEORAPLAY_Decoder *THEORAPLAY_startDecode(THEORAPLAY_Io *io,
|
||||
const unsigned int maxframes,
|
||||
THEORAPLAY_VideoFormat vidfmt)
|
||||
{
|
||||
TheoraDecoder *ctx = NULL;
|
||||
ConvertVideoFrameFn vidcvt = NULL;
|
||||
|
||||
switch (vidfmt)
|
||||
{
|
||||
// !!! FIXME: current expects TH_PF_420.
|
||||
#define VIDCVT(t) case THEORAPLAY_VIDFMT_##t: vidcvt = ConvertVideoFrame420To##t; break;
|
||||
VIDCVT(YV12)
|
||||
VIDCVT(IYUV)
|
||||
VIDCVT(RGB)
|
||||
VIDCVT(RGBA)
|
||||
#undef VIDCVT
|
||||
default: goto startdecode_failed; // invalid/unsupported format.
|
||||
} // switch
|
||||
|
||||
ctx = (TheoraDecoder *) malloc(sizeof (TheoraDecoder));
|
||||
if (ctx == NULL)
|
||||
goto startdecode_failed;
|
||||
|
||||
memset(ctx, '\0', sizeof (TheoraDecoder));
|
||||
ctx->maxframes = maxframes;
|
||||
ctx->vidfmt = vidfmt;
|
||||
ctx->vidcvt = vidcvt;
|
||||
ctx->io = io;
|
||||
|
||||
if (Mutex_Create(ctx) == 0)
|
||||
{
|
||||
ctx->thread_created = (Thread_Create(ctx, WorkerThreadEntry) == 0);
|
||||
if (ctx->thread_created)
|
||||
return (THEORAPLAY_Decoder *) ctx;
|
||||
} // if
|
||||
|
||||
Mutex_Destroy(ctx->lock);
|
||||
|
||||
startdecode_failed:
|
||||
io->close(io);
|
||||
free(ctx);
|
||||
return NULL;
|
||||
} // THEORAPLAY_startDecode
|
||||
|
||||
|
||||
void THEORAPLAY_stopDecode(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
TheoraDecoder *ctx = (TheoraDecoder *) decoder;
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
if (ctx->thread_created)
|
||||
{
|
||||
ctx->halt = 1;
|
||||
Thread_Join(ctx->worker);
|
||||
Mutex_Destroy(ctx->lock);
|
||||
} // if
|
||||
|
||||
VideoFrame *videolist = ctx->videolist;
|
||||
while (videolist)
|
||||
{
|
||||
VideoFrame *next = videolist->next;
|
||||
free(videolist->pixels);
|
||||
free(videolist);
|
||||
videolist = next;
|
||||
} // while
|
||||
|
||||
AudioPacket *audiolist = ctx->audiolist;
|
||||
while (audiolist)
|
||||
{
|
||||
AudioPacket *next = audiolist->next;
|
||||
free(audiolist->samples);
|
||||
free(audiolist);
|
||||
audiolist = next;
|
||||
} // while
|
||||
|
||||
free(ctx);
|
||||
} // THEORAPLAY_stopDecode
|
||||
|
||||
|
||||
int THEORAPLAY_isDecoding(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
TheoraDecoder *ctx = (TheoraDecoder *) decoder;
|
||||
int retval = 0;
|
||||
if (ctx)
|
||||
{
|
||||
Mutex_Lock(ctx->lock);
|
||||
retval = ( ctx && (ctx->audiolist || ctx->videolist ||
|
||||
(ctx->thread_created && !ctx->thread_done)) );
|
||||
Mutex_Unlock(ctx->lock);
|
||||
} // if
|
||||
return retval;
|
||||
} // THEORAPLAY_isDecoding
|
||||
|
||||
|
||||
#define GET_SYNCED_VALUE(typ, defval, decoder, member) \
|
||||
TheoraDecoder *ctx = (TheoraDecoder *) decoder; \
|
||||
typ retval = defval; \
|
||||
if (ctx) { \
|
||||
Mutex_Lock(ctx->lock); \
|
||||
retval = ctx->member; \
|
||||
Mutex_Unlock(ctx->lock); \
|
||||
} \
|
||||
return retval;
|
||||
|
||||
int THEORAPLAY_isInitialized(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
GET_SYNCED_VALUE(int, 0, decoder, prepped);
|
||||
} // THEORAPLAY_isInitialized
|
||||
|
||||
|
||||
int THEORAPLAY_hasVideoStream(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
GET_SYNCED_VALUE(int, 0, decoder, hasvideo);
|
||||
} // THEORAPLAY_hasVideoStream
|
||||
|
||||
|
||||
int THEORAPLAY_hasAudioStream(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
GET_SYNCED_VALUE(int, 0, decoder, hasaudio);
|
||||
} // THEORAPLAY_hasAudioStream
|
||||
|
||||
|
||||
unsigned int THEORAPLAY_availableVideo(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
GET_SYNCED_VALUE(unsigned int, 0, decoder, videocount);
|
||||
} // THEORAPLAY_hasAudioStream
|
||||
|
||||
|
||||
unsigned int THEORAPLAY_availableAudio(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
GET_SYNCED_VALUE(unsigned int, 0, decoder, audioms);
|
||||
} // THEORAPLAY_hasAudioStream
|
||||
|
||||
|
||||
int THEORAPLAY_decodingError(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
GET_SYNCED_VALUE(int, 0, decoder, decode_error);
|
||||
} // THEORAPLAY_decodingError
|
||||
|
||||
|
||||
const THEORAPLAY_AudioPacket *THEORAPLAY_getAudio(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
TheoraDecoder *ctx = (TheoraDecoder *) decoder;
|
||||
AudioPacket *retval;
|
||||
|
||||
Mutex_Lock(ctx->lock);
|
||||
retval = ctx->audiolist;
|
||||
if (retval)
|
||||
{
|
||||
ctx->audioms -= retval->playms;
|
||||
ctx->audiolist = retval->next;
|
||||
retval->next = NULL;
|
||||
if (ctx->audiolist == NULL)
|
||||
ctx->audiolisttail = NULL;
|
||||
} // if
|
||||
Mutex_Unlock(ctx->lock);
|
||||
|
||||
return retval;
|
||||
} // THEORAPLAY_getAudio
|
||||
|
||||
|
||||
void THEORAPLAY_freeAudio(const THEORAPLAY_AudioPacket *_item)
|
||||
{
|
||||
THEORAPLAY_AudioPacket *item = (THEORAPLAY_AudioPacket *) _item;
|
||||
if (item != NULL)
|
||||
{
|
||||
assert(item->next == NULL);
|
||||
free(item->samples);
|
||||
free(item);
|
||||
} // if
|
||||
} // THEORAPLAY_freeAudio
|
||||
|
||||
|
||||
const THEORAPLAY_VideoFrame *THEORAPLAY_getVideo(THEORAPLAY_Decoder *decoder)
|
||||
{
|
||||
TheoraDecoder *ctx = (TheoraDecoder *) decoder;
|
||||
VideoFrame *retval;
|
||||
|
||||
Mutex_Lock(ctx->lock);
|
||||
retval = ctx->videolist;
|
||||
if (retval)
|
||||
{
|
||||
ctx->videolist = retval->next;
|
||||
retval->next = NULL;
|
||||
if (ctx->videolist == NULL)
|
||||
ctx->videolisttail = NULL;
|
||||
assert(ctx->videocount > 0);
|
||||
ctx->videocount--;
|
||||
} // if
|
||||
Mutex_Unlock(ctx->lock);
|
||||
|
||||
return retval;
|
||||
} // THEORAPLAY_getVideo
|
||||
|
||||
|
||||
void THEORAPLAY_freeVideo(const THEORAPLAY_VideoFrame *_item)
|
||||
{
|
||||
THEORAPLAY_VideoFrame *item = (THEORAPLAY_VideoFrame *) _item;
|
||||
if (item != NULL)
|
||||
{
|
||||
assert(item->next == NULL);
|
||||
free(item->pixels);
|
||||
free(item);
|
||||
} // if
|
||||
} // THEORAPLAY_freeVideo
|
||||
|
||||
// end of theoraplay.cpp ...
|
||||
|
||||
85
rcbasic_runtime/theoraplay.h
Normal file
85
rcbasic_runtime/theoraplay.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* TheoraPlay; multithreaded Ogg Theora/Ogg Vorbis decoding.
|
||||
*
|
||||
* Please see the file LICENSE.txt in the source's root directory.
|
||||
*
|
||||
* This file written by Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
#ifndef _INCL_THEORAPLAY_H_
|
||||
#define _INCL_THEORAPLAY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct THEORAPLAY_Io THEORAPLAY_Io;
|
||||
struct THEORAPLAY_Io
|
||||
{
|
||||
long (*read)(THEORAPLAY_Io *io, void *buf, long buflen);
|
||||
void (*close)(THEORAPLAY_Io *io);
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
typedef struct THEORAPLAY_Decoder THEORAPLAY_Decoder;
|
||||
|
||||
/* YV12 is YCrCb, not YCbCr; that's what SDL uses for YV12 overlays. */
|
||||
typedef enum THEORAPLAY_VideoFormat
|
||||
{
|
||||
THEORAPLAY_VIDFMT_YV12, /* NTSC colorspace, planar YCrCb 4:2:0 */
|
||||
THEORAPLAY_VIDFMT_IYUV, /* NTSC colorspace, planar YCbCr 4:2:0 */
|
||||
THEORAPLAY_VIDFMT_RGB, /* 24 bits packed pixel RGB */
|
||||
THEORAPLAY_VIDFMT_RGBA /* 32 bits packed pixel RGBA (full alpha). */
|
||||
} THEORAPLAY_VideoFormat;
|
||||
|
||||
typedef struct THEORAPLAY_VideoFrame
|
||||
{
|
||||
unsigned int playms;
|
||||
double fps;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
THEORAPLAY_VideoFormat format;
|
||||
unsigned char *pixels;
|
||||
struct THEORAPLAY_VideoFrame *next;
|
||||
} THEORAPLAY_VideoFrame;
|
||||
|
||||
typedef struct THEORAPLAY_AudioPacket
|
||||
{
|
||||
unsigned int playms; /* playback start time in milliseconds. */
|
||||
int channels;
|
||||
int freq;
|
||||
int frames;
|
||||
float *samples; /* frames * channels float32 samples. */
|
||||
struct THEORAPLAY_AudioPacket *next;
|
||||
} THEORAPLAY_AudioPacket;
|
||||
|
||||
THEORAPLAY_Decoder *THEORAPLAY_startDecodeFile(const char *fname,
|
||||
const unsigned int maxframes,
|
||||
THEORAPLAY_VideoFormat vidfmt);
|
||||
THEORAPLAY_Decoder *THEORAPLAY_startDecode(THEORAPLAY_Io *io,
|
||||
const unsigned int maxframes,
|
||||
THEORAPLAY_VideoFormat vidfmt);
|
||||
void THEORAPLAY_stopDecode(THEORAPLAY_Decoder *decoder);
|
||||
|
||||
int THEORAPLAY_isDecoding(THEORAPLAY_Decoder *decoder);
|
||||
int THEORAPLAY_decodingError(THEORAPLAY_Decoder *decoder);
|
||||
int THEORAPLAY_isInitialized(THEORAPLAY_Decoder *decoder);
|
||||
int THEORAPLAY_hasVideoStream(THEORAPLAY_Decoder *decoder);
|
||||
int THEORAPLAY_hasAudioStream(THEORAPLAY_Decoder *decoder);
|
||||
unsigned int THEORAPLAY_availableVideo(THEORAPLAY_Decoder *decoder);
|
||||
unsigned int THEORAPLAY_availableAudio(THEORAPLAY_Decoder *decoder);
|
||||
|
||||
const THEORAPLAY_AudioPacket *THEORAPLAY_getAudio(THEORAPLAY_Decoder *decoder);
|
||||
void THEORAPLAY_freeAudio(const THEORAPLAY_AudioPacket *item);
|
||||
|
||||
const THEORAPLAY_VideoFrame *THEORAPLAY_getVideo(THEORAPLAY_Decoder *decoder);
|
||||
void THEORAPLAY_freeVideo(const THEORAPLAY_VideoFrame *item);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* include-once blocker. */
|
||||
|
||||
/* end of theoraplay.h ... */
|
||||
|
||||
74
rcbasic_runtime/theoraplay_cvtrgb.h
Normal file
74
rcbasic_runtime/theoraplay_cvtrgb.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* TheoraPlay; multithreaded Ogg Theora/Ogg Vorbis decoding.
|
||||
*
|
||||
* Please see the file LICENSE.txt in the source's root directory.
|
||||
*
|
||||
* This file written by Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
#if !THEORAPLAY_INTERNAL
|
||||
#error Do not include this in your app. It is used internally by TheoraPlay.
|
||||
#endif
|
||||
|
||||
static unsigned char *THEORAPLAY_CVT_FNNAME_420(const th_info *tinfo,
|
||||
const th_ycbcr_buffer ycbcr)
|
||||
{
|
||||
const int w = tinfo->pic_width;
|
||||
const int h = tinfo->pic_height;
|
||||
unsigned char *pixels = (unsigned char *) malloc(w * h * 4);
|
||||
if (pixels)
|
||||
{
|
||||
unsigned char *dst = pixels;
|
||||
const int ystride = ycbcr[0].stride;
|
||||
const int cbstride = ycbcr[1].stride;
|
||||
const int crstride = ycbcr[2].stride;
|
||||
const int yoff = (tinfo->pic_x & ~1) + ystride * (tinfo->pic_y & ~1);
|
||||
const int cboff = (tinfo->pic_x / 2) + (cbstride) * (tinfo->pic_y / 2);
|
||||
const unsigned char *py = ycbcr[0].data + yoff;
|
||||
const unsigned char *pcb = ycbcr[1].data + cboff;
|
||||
const unsigned char *pcr = ycbcr[2].data + cboff;
|
||||
int posx, posy;
|
||||
|
||||
for (posy = 0; posy < h; posy++)
|
||||
{
|
||||
for (posx = 0; posx < w; posx++)
|
||||
{
|
||||
// http://www.theora.org/doc/Theora.pdf, 1.1 spec,
|
||||
// chapter 4.2 (Y'CbCr -> Y'PbPr -> R'G'B')
|
||||
// These constants apparently work for NTSC _and_ PAL/SECAM.
|
||||
const float yoffset = 16.0f;
|
||||
const float yexcursion = 219.0f;
|
||||
const float cboffset = 128.0f;
|
||||
const float cbexcursion = 224.0f;
|
||||
const float croffset = 128.0f;
|
||||
const float crexcursion = 224.0f;
|
||||
const float kr = 0.299f;
|
||||
const float kb = 0.114f;
|
||||
|
||||
const float y = (((float) py[posx]) - yoffset) / yexcursion;
|
||||
const float pb = (((float) pcb[posx / 2]) - cboffset) / cbexcursion;
|
||||
const float pr = (((float) pcr[posx / 2]) - croffset) / crexcursion;
|
||||
const float r = (y + (2.0f * (1.0f - kr) * pr)) * 255.0f;
|
||||
const float g = (y - ((2.0f * (((1.0f - kb) * kb) / ((1.0f - kb) - kr))) * pb) - ((2.0f * (((1.0f - kr) * kr) / ((1.0f - kb) - kr))) * pr)) * 255.0f;
|
||||
const float b = (y + (2.0f * (1.0f - kb) * pb)) * 255.0f;
|
||||
|
||||
*(dst++) = (unsigned char) ((r < 0.0f) ? 0.0f : (r > 255.0f) ? 255.0f : r);
|
||||
*(dst++) = (unsigned char) ((g < 0.0f) ? 0.0f : (g > 255.0f) ? 255.0f : g);
|
||||
*(dst++) = (unsigned char) ((b < 0.0f) ? 0.0f : (b > 255.0f) ? 255.0f : b);
|
||||
#if THEORAPLAY_CVT_RGB_ALPHA
|
||||
*(dst++) = 0xFF;
|
||||
#endif
|
||||
} // for
|
||||
|
||||
// adjust to the start of the next line.
|
||||
py += ystride;
|
||||
pcb += cbstride * (posy % 2);
|
||||
pcr += crstride * (posy % 2);
|
||||
} // for
|
||||
} // if
|
||||
|
||||
return pixels;
|
||||
} // THEORAPLAY_CVT_FNNAME_420
|
||||
|
||||
// end of theoraplay_cvtrgb.h ...
|
||||
|
||||
Reference in New Issue
Block a user