{"id":17449692,"url":"https://github.com/bolner/gw-basic-3d","last_synced_at":"2026-01-12T06:42:43.063Z","repository":{"id":148174539,"uuid":"210198637","full_name":"bolner/GW-BASIC-3D","owner":"bolner","description":"3D Graphics in GW-Basic","archived":false,"fork":false,"pushed_at":"2019-09-22T21:18:20.000Z","size":156,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-08T12:46:58.682Z","etag":null,"topics":["3d","basic","dos","graphics","gwbasic"],"latest_commit_sha":null,"homepage":null,"language":"Visual Basic","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bolner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-22T18:56:36.000Z","updated_at":"2023-01-13T02:36:02.000Z","dependencies_parsed_at":"2023-05-19T09:00:37.911Z","dependency_job_id":null,"html_url":"https://github.com/bolner/GW-BASIC-3D","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bolner%2FGW-BASIC-3D","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bolner%2FGW-BASIC-3D/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bolner%2FGW-BASIC-3D/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bolner%2FGW-BASIC-3D/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bolner","download_url":"https://codeload.github.com/bolner/GW-BASIC-3D/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246901424,"owners_count":20852215,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d","basic","dos","graphics","gwbasic"],"created_at":"2024-10-17T21:47:04.796Z","updated_at":"2026-01-12T06:42:43.029Z","avatar_url":"https://github.com/bolner.png","language":"Visual Basic","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GW-BASIC-3D\n\nSimple 3D Graphics in GW-Basic\n\n[![Watch the video](youtube_tumbler.png)](https://www.youtube.com/watch?v=a0l9GFDluOo)\n\nNostalgy might've certainly been among the motivations behind this funny project of mine which brings a long dead programming environment, the [Microsoft GW-Basic](https://en.wikipedia.org/wiki/GW-BASIC), back to the land of the living.\n\nThe program [G3D.BAS](G3D.BAS) implements 3D graphics through 4x4 transformation matrices. A spehere is rotated around one of its poles.\n\nI was curious how it would run on a 386 DX. I found it slow, therefore I refactored the program a bit to pre-render the points with the screen coordinates. You can give it a try:\n\nYou can run the file [in the attached ZIP](Binary_G3D.zip) by executing an original `GWBASIC.EXE` inside a `DosBox` emulator. The GW-Basic interpreter handled tokenized/binary files only, and it's not able to read normal text files. (I entered the code on the native user interface.)\n\nDosBox configuration to get the performance of a `386 DX` machine (increase the `cycles` for speedup):\n\n    fullresolution=desktop\n    windowresolution=1280x700\n    output=opengl\n    aspect=true\n    scaler=supereagle\n    cputype=386\n    cycles=2150\n\nI've converted the tokenized file to text, using the [danvk/gwbasic-decoder](https://github.com/danvk/gwbasic-decoder) tool, in which project I also participated in the past weeks.\n\nThe source code in text format:\n```basic\n   10 REM *************************************************************\n   20 REM * 3D Graphics program. Written by: Tamas Bolner, 2019-09-22 *\n   30 REM *************************************************************\n   35 KEY OFF\n   36 SCREEN 0, 0, 0, 0: CLS\n   40 ACTIVE = 0: REM The screen where we draw. If 0 then 1 is shown.\n   45 RADIUS = 50: BASE = 11: POINTS = BASE * BASE: MAXFRAME = 20\n   50 DIM M(6, 4, 4): REM The global array of all 4x4 matrices\n   60 DIM P(POINTS + 1, 3)\n   65 DIM H(MAXFRAME + 1, POINTS, 2)\n   70 REM *******************************\n   80 REM * Generate the shape (sphere) *\n   90 REM *******************************\n   95 PRINT \"Constructing the object\"\n  100 PI = 3.14159\n  115 HALF = (BASE - 1) / 2\n  120 FOR I = 0 TO BASE - 1: FOR J = 0 TO BASE - 1\n  122 D = (I - HALF) / HALF: CR = SQR(1 - D*D) * RADIUS\n  130 P(I*BASE + J, 0) = COS((2*PI/(BASE-1)) * J) * CR\n  140 P(I*BASE + J, 1) = SIN((2*PI/(BASE-1)) * J) * CR\n  150 P(I*BASE + J, 2) = (RADIUS/BASE) * I * 2.2\n  160 NEXT J: NEXT I\n 1000 REM ********************************\n 1010 REM * Render points using matrices *\n 1020 REM ********************************\n 1040 PRINT \"Rendering the screen coordinates of the points\"\n 1050 ALPHA = 0: AI = PI*2 / (10 * BASE)\n 1060 FOR I=0 TO .96 STEP .05\n 1065 PRINT INT(I*100);\"% \";\n 1070 BETA = PI * 2 * I: FRAME = INT(I * 20)\n 1080 SY = 1: SX = ALPHA: GOSUB 6230: REM M(1) = rotZ(ALPHA)\n 1090 SY = 2: SX = BETA: GOSUB 6130: REM M(2) = rotY(BETA)\n 1100 SW = 3: SX = 0: SY = 0: SZ = 60: GOSUB 6010: REM M(3) = Translation\n 1110 SZ = 4: SX = 2: SY = 1: GOSUB 5100: REM M(4) = M(2)*M(1)\n 1120 SZ = 5: SX = 3: SY = 4: GOSUB 5100: REM M(5) = M(3)*M(4)\n 1130 FOR SX = 0 TO POINTS - 1: SY = 5: GOSUB 5640\n 1132 SY = FRAME: GOSUB 5825: REM Projection\n 1136 NEXT SX\n 1160 ALPHA = ALPHA + AI\n 1170 NEXT I\n 2000 REM *************\n 2010 REM * Animation *\n 2020 REM *************\n 2100 FOR I = 0 TO 19\n 2110 GOSUB 5030: REM Switch screens\n 2460 SX = I: GOSUB 5870: REM Display\n 2470 A$ = INKEY$: IF A$ \u003c\u003e \"\" THEN SCREEN 9, 0, ACTIVE, ACTIVE: END\n 2480 NEXT I\n 2600 GOTO 2100\n 5000 REM *****************************\n 5010 REM * Subroutine: Switch screen *\n 5020 REM *****************************\n 5030 ACTIVE = 1 - ACTIVE\n 5040 SCREEN 9, 0, ACTIVE, 1 - ACTIVE\n 5050 CLS 1\n 5060 RETURN\n 5070 REM *********************************\n 5080 REM * Subroutine: Multiply matrices *\n 5085 REM *   M(SZ) = M(SX) * M(SY)       *\n 5090 REM *********************************\n 5100 M(SZ,0,0) = M(SX,0,0)*M(SY,0,0) + M(SX,1,0)*M(SY,0,1) + M(SX,2,0)*M(SY,0,2) + M(SY,3,0)*M(SY,0,3)\n 5110 M(SZ,0,1) = M(SX,0,1)*M(SY,0,0) + M(SX,1,1)*M(SY,0,1) + M(SX,2,1)*M(SY,0,2) + M(SY,3,1)*M(SY,0,3)\n 5120 M(SZ,0,2) = M(SX,0,2)*M(SY,0,0) + M(SX,1,2)*M(SY,0,1) + M(SX,2,2)*M(SY,0,2) + M(SY,3,2)*M(SY,0,3)\n 5130 M(SZ,0,3) = M(SX,0,3)*M(SY,0,0) + M(SX,1,3)*M(SY,0,1) + M(SX,2,3)*M(SY,0,2) + M(SY,3,3)*M(SY,0,3)\n 5200 M(SZ,1,0) = M(SX,0,0)*M(SY,1,0) + M(SX,1,0)*M(SY,1,1) + M(SX,2,0)*M(SY,1,2) + M(SY,3,0)*M(SY,1,3)\n 5210 M(SZ,1,1) = M(SX,0,1)*M(SY,1,0) + M(SX,1,1)*M(SY,1,1) + M(SX,2,1)*M(SY,1,2) + M(SY,3,1)*M(SY,1,3)\n 5220 M(SZ,1,2) = M(SX,0,2)*M(SY,1,0) + M(SX,1,2)*M(SY,1,1) + M(SX,2,2)*M(SY,1,2) + M(SY,3,2)*M(SY,1,3)\n 5230 M(SZ,1,3) = M(SX,0,3)*M(SY,1,0) + M(SX,1,3)*M(SY,1,1) + M(SX,2,3)*M(SY,1,2) + M(SY,3,3)*M(SY,1,3)\n 5300 M(SZ,2,0) = M(SX,0,0)*M(SY,2,0) + M(SX,1,0)*M(SY,2,1) + M(SX,2,0)*M(SY,2,2) + M(SY,3,0)*M(SY,2,3)\n 5310 M(SZ,2,1) = M(SX,0,1)*M(SY,2,0) + M(SX,1,1)*M(SY,2,1) + M(SX,2,1)*M(SY,2,2) + M(SY,3,1)*M(SY,2,3)\n 5320 M(SZ,2,2) = M(SX,0,2)*M(SY,2,0) + M(SX,1,2)*M(SY,2,1) + M(SX,2,2)*M(SY,2,2) + M(SY,3,2)*M(SY,2,3)\n 5330 M(SZ,2,3) = M(SX,0,3)*M(SY,2,0) + M(SX,1,3)*M(SY,2,1) + M(SX,2,3)*M(SY,2,2) + M(SY,3,3)*M(SY,2,3)\n 5400 M(SZ,3,0) = M(SX,0,0)*M(SY,3,0) + M(SX,1,0)*M(SY,3,1) + M(SX,2,0)*M(SY,3,2) + M(SY,3,0)*M(SY,3,3)\n 5410 M(SZ,3,1) = M(SX,0,1)*M(SY,3,0) + M(SX,1,1)*M(SY,3,1) + M(SX,2,1)*M(SY,3,2) + M(SY,3,1)*M(SY,3,3)\n 5420 M(SZ,3,2) = M(SX,0,2)*M(SY,3,0) + M(SX,1,2)*M(SY,3,1) + M(SX,2,2)*M(SY,3,2) + M(SY,3,2)*M(SY,3,3)\n 5430 M(SZ,3,3) = M(SX,0,3)*M(SY,3,0) + M(SX,1,3)*M(SY,3,1) + M(SX,2,3)*M(SY,3,2) + M(SY,3,3)*M(SY,3,3)\n 5440 RETURN\n 5600 REM ***************************************************\n 5610 REM * Subroutine: Left-multiply a point with a matrix *\n 5620 REM *    P(POINTS) = M(SY) * P(SX)                    *\n 5630 REM ***************************************************\n 5640 P(POINTS,0) = M(SY,0,0)*P(SX,0) + M(SY,1,0)*P(SX,1) + M(SY,2,0)*P(SX,2) + M(SY,3,0)\n 5650 P(POINTS,1) = M(SY,0,1)*P(SX,0) + M(SY,1,1)*P(SX,1) + M(SY,2,1)*P(SX,2) + M(SY,3,1)\n 5660 P(POINTS,2) = M(SY,0,2)*P(SX,0) + M(SY,1,2)*P(SX,1) + M(SY,2,2)*P(SX,2) + M(SY,3,2)\n 5670 RETURN\n 5800 REM **********************************\n 5810 REM * Subroutine: Plane intersection *\n 5815 REM *  H(SY, SX) = 2D point          *\n 5820 REM **********************************\n 5825 SF = -150: REM The Z coordinate of the focal point\n 5840 H(SY,SX,0) = -SF*P(POINTS,0) * 2 / (P(POINTS,2)-SF)\n 5850 H(SY,SX,1) = -SF*P(POINTS,1) * 2 / (P(POINTS,2)-SF)\n 5860 RETURN\n 5861 REM ***********************\n 5862 REM * Subroutine: Display *\n 5863 REM *   SX: Current frame *\n 5865 REM ***********************\n 5870 FOR SI = 0 TO BASE - 2: FOR SJ = 0 TO BASE - 2\n 5875 ST = SI * BASE + SJ\n 5880 SX1 = H(SX, ST, 0) + 320: SY1 = 175 - H(SX, ST, 1)\n 5885 ST2 = ST + BASE\n 5890 SX2 = H(SX, ST2, 0) + 320: SY2 = 175 - H(SX, ST2, 1)\n 5895 ST2 = ST + 1\n 5900 SX3 = H(SX, ST2, 0) + 320: SY3 = 175 - H(SX, ST2, 1)\n 5910 LINE (SX1, SY1) - (SX2, SY2)\n 5920 LINE (SX1, SY1) - (SX3, SY3)\n 5930 NEXT SJ: NEXT SI\n 5940 RETURN\n 6000 REM *****************************************\n 6010 REM * Subroutine: Create translation matrix *\n 6015 REM *   M(SW) = t(SX, SY, SZ)               *\n 6020 REM *****************************************\n 6030 M(SW,0,0) = 1: M(SW,1,1) = 1: M(SW,2,2) = 1: M(SW,3,3) = 1\n 6040 M(SW,1,0) = 0: M(SW,2,0) = 0: M(SW,0,1) = 0: M(SW,0,2) = 0: M(SW,0,3) = 0\n 6050 M(SW,1,2) = 0: M(SW,1,3) = 0: M(SW,2,3) = 0: M(SW,2,1) = 0\n 6060 M(SW,3,0) = SX: M(SW,3,1) = SY: M(SW,3,2) = SZ\n 6070 RETURN\n 6100 REM *****************************************************\n 6110 REM * Subroutine: Create rotation matrix: around Y axis *\n 6115 REM *   M(SY) = rotY(SX)                                *\n 6120 REM *****************************************************\n 6130 M(SY,0,0) = COS(SX): M(SY,1,0) = 0: M(SY,2,0) = SIN(SX): M(SY,3,0) = 0\n 6140 M(SY,0,1) = 0: M(SY,1,1) = 1: M(SY,2,1) = 0: M(SY,3,1) = 0\n 6150 M(SY,0,2) = -SIN(SX): M(SY,1,2) = 0: M(SY,2,2) = COS(SX): M(SY,3,2) = 0\n 6160 M(SY,0,3) = 0: M(SY,1,3) = 0: M(SY,2,3) = 0: M(SY,3,3) = 1\n 6170 RETURN\n 6200 REM *****************************************************\n 6210 REM * Subroutine: Create rotation matrix: around Z axis *\n 6215 REM *   M(SY) = rotZ(SX)                                *\n 6220 REM *****************************************************\n 6230 M(SY,0,0) = COS(SX): M(SY,1,0) = SIN(SX): M(SY,2,0) = 0: M(SY,3,0) = 0\n 6240 M(SY,0,1) = -SIN(SX): M(SY,1,1) = COS(SX): M(SY,2,1) = 0: M(SY,3,1) = 0\n 6250 M(SY,0,2) = 0: M(SY,1,2) = 0: M(SY,2,2) = 1: M(SY,3,2) = 0\n 6260 M(SY,0,3) = 0: M(SY,1,3) = 0: M(SY,2,3) = 0: M(SY,3,3) = 1\n 6270 RETURN\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbolner%2Fgw-basic-3d","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbolner%2Fgw-basic-3d","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbolner%2Fgw-basic-3d/lists"}