Initial Commit

This commit is contained in:
n00b87
2024-02-10 11:27:02 -06:00
parent a749abe795
commit 692f8f342e
31 changed files with 32686 additions and 0 deletions

BIN
icon/rcbasic.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

BIN
icon/rcbasic1.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
icon/rcbasic2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View 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
View 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

View 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)

View 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

View 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

File diff suppressed because it is too large Load Diff

48
rcbasic_build/keywords.h Normal file
View 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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

20
rcbasic_build/rc_debug.h Normal file
View 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
View 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

View 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

File diff suppressed because it is too large Load Diff

1052
rcbasic_build/tokenizer.h Normal file

File diff suppressed because it is too large Load Diff

285
rcbasic_build/vm_asm Normal file
View 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

File diff suppressed because it is too large Load Diff

1417
rcbasic_runtime/rc_defines.h Normal file

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

6502
rcbasic_runtime/rc_media.h Normal file

File diff suppressed because it is too large Load Diff

View 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

View 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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
MAINICON ICON "rcbasic.ico"

View 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 ...

View 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 ... */

View 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 ...