Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - Kitty Hello

#1
Announcements / Forum Update
2023-Apr-27
I hope everything is working. Does anyone need a tapatalk plugin? I hope I can get rid of it.
#2
Tutorials / Chat.GPT
2023-Apr-21
I asked Chat:GPT to write a GLBasic program, that shows a starfield, and, with the exception of CLS instead of CLEARSCREEN, it just worked out of the box. Awesome :)
#3
Hello. Now it's me having trouble. I deleted the android_studio folder and re-created everything. Then fired up the freshly installed Android Studio and got some errors:
Code (glbasic) Select

cvc-complex-type.2.4.a: Invalid content was found starting with element 'extension-level'. One of '{layoutlib}' is expected.
cvc-complex-type.2.4.a: Invalid content was found starting with element 'base-extension'. One of '{codename, tag}' is expected.

> java.lang.NullPointerException (no error message)

* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Exception is:
org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':app'.
at org.gradle.configuration.project.LifecycleProjectEvaluator.wrapException(LifecycleProjectEvaluator.java:79)
at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:72)
at org.gradle.configuration.project.LifecycleProjectEvaluator.access$600(LifecycleProjectEvaluator.java:53)
at org.gradle.configuration.project.LifecycleProjectEvaluator$NotifyAfterEvaluate.run(LifecycleProjectEvaluator.java:198)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject$1.run(LifecycleProjectEvaluator.java:111)
at org.gradle.internal.Factories$1.create(Factories.java:25)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:183)
at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:40)
at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withProjectLock(DefaultProjectStateRegistry.java:226)
at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:220)
at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:186)
at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:95)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:67)
at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:693)
at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:141)
at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:35)
at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:62)
at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:41)
at org.gradle.initialization.DefaultGradleLauncher$ConfigureBuild.run(DefaultGradleLauncher.java:302)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
at org.gradle.initialization.DefaultGradleLauncher.configureBuild(DefaultGradleLauncher.java:210)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:151)
at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:134)
at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:58)
at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:55)
at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:82)
at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:75)
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:183)
at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:40)
at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:75)
at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:55)
at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:60)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:58)
at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32)
at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:39)
at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:49)
at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:44)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:315)
at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:305)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:101)
at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:44)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:49)
at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:46)
at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:78)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:46)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:31)
at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:42)
at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:28)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:78)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:52)
at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:59)
at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:36)
at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:68)
at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:38)
at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:37)
at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:26)
at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43)
at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29)
at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:60)
at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:32)
at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55)
at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:41)
at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:48)
at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:32)
at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
at org.gradle.util.Swapper.swap(Swapper.java:38)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:62)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:81)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:295)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: java.lang.NullPointerException
at com.android.build.gradle.internal.ndk.NdkHandler.getPlatformVersion(NdkHandler.java:121)
at com.android.build.gradle.internal.ndk.NdkHandler.supports64Bits(NdkHandler.java:221)
at com.android.build.gradle.internal.ndk.NdkHandler.getSupportedAbis(NdkHandler.java:269)
at com.android.build.gradle.tasks.ExternalNativeJsonGenerator.createImpl(ExternalNativeJsonGenerator.java:563)
at com.android.build.gradle.tasks.ExternalNativeJsonGenerator.create(ExternalNativeJsonGenerator.java:480)
at com.android.build.gradle.internal.TaskManager.createExternalNativeBuildJsonGenerators(TaskManager.java:1519)
...
[/ocde]

When I try to build, I get:
[code=glbasic]
java.lang.IllegalArgumentException: Each request requires the same not null build mode to be set
at com.android.tools.idea.gradle.project.build.invoker.GradleBuildInvokerImpl.executeAssembleTasks(GradleBuildInvokerImpl.kt:165)
at com.android.tools.idea.gradle.project.build.invoker.GradleBuildInvokerImpl.assemble(GradleBuildInvokerImpl.kt:211)
at com.android.tools.idea.gradle.project.build.invoker.GradleBuildInvokerImpl.assemble(GradleBuildInvokerImpl.kt:205)
at com.android.tools.idea.gradle.actions.MakeGradleProjectAction.doPerform(MakeGradleProjectAction.java:45)
at com.android.tools.idea.gradle.actions.AndroidStudioGradleAction.actionPerformed(AndroidStudioGradleAction.java:63)
at com.intellij.openapi.actionSystem.ex.ActionUtil.lambda$performActionDumbAwareWithCallbacks$4(ActionUtil.java:239)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.java:260)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAwareWithCallbacks(ActionUtil.java:239)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem$ActionTransmitter.lambda$performAction$0(ActionMenuItem.java:277)
at com.intellij.openapi.wm.impl.FocusManagerImpl.runOnOwnContext(FocusManagerImpl.java:236)
at com.intellij.openapi.wm.impl.IdeFocusManagerImpl.runOnOwnContext(IdeFocusManagerImpl.java:67)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem$ActionTransmitter.performAction(ActionMenuItem.java:269)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem$ActionTransmitter.actionPerformed(ActionMenuItem.java:284)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem.lambda$fireActionPerformed$2(ActionMenuItem.java:111)
at com.intellij.openapi.application.TransactionGuardImpl.performUserActivity(TransactionGuardImpl.java:94)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem.fireActionPerformed(ActionMenuItem.java:111)
at com.intellij.ui.plaf.beg.BegMenuItemUI.doClick(BegMenuItemUI.java:541)
at com.intellij.ui.plaf.beg.BegMenuItemUI$MyMouseInputHandler.mouseReleased(BegMenuItemUI.java:571)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6654)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3345)
at java.desktop/java.awt.Component.processEvent(Component.java:6419)
at java.desktop/java.awt.Container.processEvent(Container.java:2263)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5029)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2790)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4861)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:891)
at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:820)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:757)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$6(IdeEventQueue.java:447)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:818)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$7(IdeEventQueue.java:446)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:805)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:498)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Can someone help me, please :)
#4
Hi,

I had to add a 3D eggplant to one of my games and noticed, that my AC3D license was too old and the uppgrade fee was raised a lot and whatnot. So I installed the new Blender 2.9 and after a few videos, I got the hang of it. It improved a LOT! If you want to do 3D, try this out.
So, the Blender export filter was broken due to API changes. I had a few nights to get that running again. The old script was about 10+ years old. :)
(reminder to myself: always comment code. Code you wrote 5 years ago is code someone else might have written...)

So, I fixed the export and found, the dda files were quite big. I inserted a scale factor for normals and vertex coordinates and now... the dda (ASCII!) file format is more compact than the ddd binary file format I used to be so proud of.

The trick is, that the vertex positions*1000 often result in numbers like "5" or "15", which is 2-3 bytes including a separating space caracter. The binary always takes 4 bytes per float. Same for the normal directions*100.
The next update will bring both, the export filter and the dda 2.0 support to you.
#5
I tell you a secret. GLBasic can load data from a memory buffer, as if it was a file. With the attached code, you can use the contents of a string to "read" it as a file. This should work for about everything. Sprites, sounds, binary files, ...

Code (glbasic) Select




LOCAL mem$ = "Hello World"
LOCAL memlen = LEN(mem$)

LOCAL file$ = MemMakeFile$(mem$)

LOCAL text$
OPENFILE(1, file$, TRUE)
READSTR 1, text$, 64
CLOSEFILE 1
STDOUT text$ + "\n"
KEYWAIT

FUNCTION foo:
ENDFUNCTION

INLINE
extern "C" {int sprintf(char *str, const char *format, ...); }
ENDINLINE


FUNCTION MemMakeFile$: BYREF data$, nofBytes = -1
IF nofBytes < 0 THEN nofBytes = LEN(data$)
LOCAL url$
LOCAL hx$ = RIGHT$("0000000000000000" + HEX$(nofBytes), 8)
INLINE
void* address = &data_Str[0];
char buffer[64];
sprintf(buffer, "%x", address);

url_Str = CGStr("mem://") + hx_Str + CGStr(".") + CGStr(buffer);
ENDINLINE


RETURN url$
ENDFUNCTION
#6
Announcements / New BETA
2021-Jun-15
Including long requested MEM2FONT and FONT2MEM commands.
#7
Here's an improved version of the Dictionary and a Sorted List for strings. I'll include that into the GLBasic Samples folder, because it's very handy, okay?
Code (glbasic) Select

// --------------------------------- //
// Project: T_Dictionary
// Start: Friday, August 16, 2019
// IDE Version: 16.252

TYPE T_DictionaryPair
key$
val$
ENDTYPE

TYPE TDictionary
pairs[] AS T_DictionaryPair

// ------------------------------------------ //
//! Get string at given key
// ------------------------------------------ //
FUNCTION get$: key$
LOCAL i% = _index(key$, FALSE)
IF i>=0 THEN RETURN self.pairs[i].val$
RETURN ""
ENDFUNCTION

// ------------------------------------------ //
//! Set string at given key
// ------------------------------------------ //
FUNCTION set%: key$, val$
LOCAL i% = _index(key$, TRUE)
self.pairs[i].val$ = val$
ENDFUNCTION

// ------------------------------------------ //
//! Get index in pairs[] for given string
// ------------------------------------------ //
FUNCTION _index%: BYREF name$, create%=TRUE
LOCAL up%, dn%, mid%
up=0; dn=LEN(self.pairs[])-1
WHILE up < dn
mid = (up+dn) / 2
IF self.pairs[mid].key$ > name$
dn=MAX(mid-1, up)
ELSE
IF self.pairs[mid].key$ < name$
up=MIN(dn, mid+1)
ELSE
RETURN mid // not bigger, not smaller, guess what!?
ENDIF
ENDIF
WEND

IF LEN(self.pairs[]) AND self.pairs[up].key$ = name$ THEN RETURN up

// not found. But must be at [up].
IF create%
dn = LEN(self.pairs[]) // one below last
REDIM self.pairs[dn+1]
FOR mid = dn TO up+1 STEP -1
self.pairs[mid] = self.pairs[mid-1]
NEXT
IF dn>0 AND self.pairs[up].key$ < name$ THEN up=up+1

ALIAS where AS self.pairs[up]
where.key$ = name$
where.val$ = ""
RETURN up
ENDIF
RETURN -1
ENDFUNCTION
ENDTYPE


TYPE TSortedSet
keys$[]

// ------------------------------------------ //
//! Get string at given key
// ------------------------------------------ //
FUNCTION isSet%: key$
LOCAL i% = _index(key$, FALSE)
IF i>=0 THEN RETURN TRUE
RETURN FALSE
ENDFUNCTION

// ------------------------------------------ //
//! Set string at given key
// ------------------------------------------ //
FUNCTION insert%: key$
_index(key$, TRUE)
ENDFUNCTION

// ------------------------------------------ //
//! Get index in pairs[] for given string
// ------------------------------------------ //
FUNCTION _index%: BYREF name$, create%=TRUE
LOCAL up%, dn%, mid%
up=0; dn=LEN(self.keys$)-1
WHILE up < dn
mid = (up+dn) / 2
IF self.keys$[mid] > name$
dn=MAX(mid-1, up)
ELSE
IF self.keys$[mid] < name$
up=MIN(dn, mid+1)
ELSE
RETURN mid // not bigger, not smaller, guess what!?
ENDIF
ENDIF
WEND

IF LEN(self.keys$[]) AND self.keys$[up] = name$ THEN RETURN up

// not found. But must be at [up].
IF create%
dn = LEN(self.keys$[]) // one below last
REDIM self.keys$[dn+1]
FOR mid = dn TO up+1 STEP -1
self.keys$[mid] = self.keys$[mid-1]
NEXT
IF dn>0 AND self.keys$[up] < name$ THEN up=up+1

self.keys$[up] = name$
RETURN up
ENDIF
RETURN -1
ENDFUNCTION
ENDTYPE



Test program
Code (glbasic) Select

LOCAL sose AS TSortedSet

sose.insert("cat")
sose.insert("mouse")
sose.insert("dog")
sose.insert("bird")
STDOUT "isset dog " + sose.isSet("dog") + "\n"
STDOUT "isset rat " + sose.isSet("rat") + "\n"
FOREACH k$ IN sose.keys$[]
STDOUT "-" + k$ + "\n"
NEXT

STDOUT "------------------\n"

LOCAL dict AS TDictionary

dict.set("cats", 5)
dict.set("mice", 7)
dict.set("dogs", "many")
dict.set("birds", "any")
STDOUT "dogs: " + dict.get$("dogs") + "\n"
STDOUT "rats: " + dict.get$("rats") + "\n"
FOREACH p IN dict.pairs[]
STDOUT "-" + p.key$ + " = " + p.val$ + "\n"
NEXT
KEYWAIT



Here's the output
Code (glbasic) Select

isset dog 1
isset rat 0
-bird
-cat
-dog
-mouse
------------------
dogs: many
rats:
-birds = any
-cats = 5
-dogs = many
-mice = 7

#8
For those of us, who are married, the current lockdown situation might be a great challenge, because women do need care, adventure and variation. Before the lockdown, this was made easy for us, because there was restaurants, day trips and gathering with friends. We could even stay out after 9pm. Remember, on our wedding day, we (hopefully) all promised to "love and care" for the bride.
For me, love, that is not "I like what you have/are", it's more a "It's not because of the one you love - it's my free will. I want to put great effort to bring her joy. Take some of her burden. ". That kind of love.
How will this work with the latest limitations put on us? I am sort of desperately clueless.
So, maybe you have better ideas that you want to share, to make our wedding promise shine brightly true in a dark world full of lies.

Rules
-Post your idea
-Don't talk about the lockdown
-Don't post your opinion on the lockdown
-Don't ask on our opinion on the lockdown
-Don't try to think logically about the lockdown
-Do not complain about the lockdown or the gouverment or anyone responsible for the lockdown.



So, what I have is:

Make a fire
If you have a garden, get some metal bowl, the bigger the better, put some dry wood on (you can get that in a supermarket, here. But also a farmer close by migtht sell you a sack). Put some liqud fire starter above and burn it. Beware, when it's cold outside, it took me a full hour to get it burning properly. Add some garden chairs, maybe two branches and some marshmellows.
It worked fine, but for sure you will have the kids attending ;). So I'd give a romance rating of 7/10.


Watch the dusk
Open google maps, find a nearby place with a hill or a small mountain, that has a road on the west side. Then find a restaurant, that offers take-away food nearby. Order food, driver to that place, pull the handbrake and keep the engine running (Yeah, sue me Greta!) and watch the sun go down. Make sure to have a pack of wet tissues in the car for the fingers. Also, this might need good timing. Alternatively, just drive to a parking lot at a lake nearby and leact the lights on, if you're too late for dawn.
We did this (again with the whole family). It's no substitute for a real restaurant, but hey, better than netflix. 6/10?
#9
Sometimes, I need vector graphics - polygons.
And designing them is always complicated. Most times, I just need 10 points.
So, I decided to make a vector format, that is editable with any text editor.

The file format is described in "Media/fileformat.plxtxt" and goes like:

#plytx - 5 byte header information. File encoding without BOM!

# --= PolyText ==-
# Polytext is a vector format, that is easy to edit
# with a text editor.

# *** SYNTAX ***
# Everything right of a '#' is considered a comment.
# lines starting with ':' are commands. Commands must be lowercase.
# whitespace between command arguments is ignored.
# arguments can be separated by whitespace. Comma ',' is treated as whitespace
# for better readability.

# *** NODES ***
# The point information is given in the 'map' command.
# Points are named:
#         0..9 A..Z a..z
# This results in max. 62 points per file.
# The above point names also are the default order of the point names.
# Point names can have gaps, so you can easily define a polygon
# by the points A C E and refer to the names range A-E.
#
# ^Y     The name '0' is a special point and refers to the origin
# |      of the local coordinate system.
# 0-->X  X positive is to the right, Y positive is towards the top.

# *** SPECIAL NODES ***
# You can embrace nodes by (), [], {} or <>
# These points get a special tag when importing them.
# It does not matter if you only write one brace, like (X or X),
# or both (X) braces.
# Also, you can set multiple braces for one point:
# {(X]> # this would set all 4 brace flags for the point 'X'.
# ASCII-art characters can be used to indicate connected lines.
# The following characters are valid:
# - + . _ / \ ^ : , ´ ` '
# The following characters are reserved for the future:
# " * ! ? & % $ §

################## COMMANDS #########################################
# *** FONT ***
# :font w h
# specify the font width and height ratio, because most text editors
# do not use quare fonts. For 'Consolas' this is like 7 18

# *** ORIGIN ***
# :origin orgx orgy
# A corrdinate that represents the position of node name '0'.
# Defaults to 0 0

# *** SCALE ***
# :scale factorx [factory]
# A factor that is applied to the X and Y coordinate of each point.
# factory equals factorx if ommited. The default scaling is 1.0.

# *** POLY ***
# :poly point_names...
# defines a polygon that is defined by the given points.
# If no points are given, the range 0-z is assumed.
# Points can either be listed individually, like:
# :poly abc efg x
# or with the range operator '-':
# :poly a-c, e-f, x
# The range operator adds all points in the ASCII-value order.
# Non existing points are simply skipped.
# You can specify a negative range for reverse direction:
# :poly c-a


# *** MAP ***
# :map
# Here, the point coordinates are given. Everything below the :map
# command is considered as part of the point list.

######################## EXAMPLE ################################
:font 7 18 # consolas
:origin 1 2
:scale 7
:poly A-Z
:poly a-d
:map
    z               __P--(Q)-----R # Example map for a C64 Thrust-Style game
A-------B       O---               # 'z' is only used as the player start position
        |       |
        |       |                  # 'A' to 'Z' is the cave polyon.
        |   0   |                  # 0 indicates the origin of coord system
        |       |
        |       |
     ___C       N
    /       b    {M_____       # The { } are cannons
   D       : :          ---L
   |     a.   :...c       K    # 'a' to 'd' form a second polygon -> an island
   |       d...            J
   E}                     I/
    F---------[G]--------H/    # Base of cave


I'm trying to do a C64 Thrust remake. Maybe.
#10
Next version will allow you to omit the 'self.' and the [] array indicators.
Here's a test example, that already compiles:

Code (glbasic) Select


TYPE T1
    i1%
ENDTYPE

TYPE TT
ia[] AS T1
ka[]
    FUNCTION foo:
    ALIAS p AS self.ia[0]
    ENDFUNCTION
ENDTYPE


FUNCTION foo: bar[]
LOCAL t AS TT

FOREACH a IN t.ia[]; a.i1=0; NEXT
FOREACH a IN t.ia  ; a.i1=0; NEXT

LOCAL a$[]
FOREACH b$ IN a$[]; b$="X"; NEXT
FOREACH b$ IN a$  ; b$="X"; NEXT

//  []     [] omited
t.ia[] = t.ia[]
t.ia = t.ia

foo(t.ka[])
foo(t.ka  )

ENDFUNCTION
#11
Attached, you'll find a wrapper for https://github.com/nayuki/QR-Code-generator/ that creates a sprite with a QR code for a given UTF-8 text.
See also the UTF-8 library, if you really need utf-8 characters (not tested).
#12
The new update 16.507 is available on STEAM now.
Among some bug fixes, this offers more possibilities on the Android platform. The mousewheel works better and DDgui got some bugfixes. (Yikes - I forgot to upload that - will soon do!)


You've seen the great efforts of spacefractal the last months. So, the Chomebook support is in and the game controlers are, too.
I fixed some bugs in the IDE and made strings even faster by implementing move semantics.
The bluetooth library is finally done and can be used for Windows and Android. Might also work on other platforms, but not tested.
For Android, I added a camera support and you can request permissions using the Android dialog popups.
Code (glbasic) Select

IF "1" == android_JAVACALL("requestPermission:android.permission.CAMERA")


To see it all in action, here's a project that uses all of them.
#13
Here's how to deal with UTF-8 strings in GLBasic. It can convert to and from ISO 8895-1 (Latin-1), so you can "PRINT" UTF-8 strings, and write UTF-8 file from latin encodings.
Code (glbasic) Select

// --------------------------------- //
// Project: UTF8- Routines
// --------------------------------- //

//! Copyvert an ansi text with codepage latin-1 (ISO 8895-1) to a UTF-8 string.
//! Prefix the UTF8_BOM$() at the start of a file when you write it to disk.
FUNCTION UTF8_fromLatin1$: latin2$
LOCAL out$
// https://stackoverflow.com/a/7904190/2721136
FOR i% = 0 TO LEN(latin2$)-1
// https://de.wikipedia.org/wiki/ISO_8859-1
LOCAL cha = ASC(latin2$, i)
IF cha < 0x80
INC out$, CHR$(cha)
ELSE
// all 11 bit codepoints (0x0 -- 0x7ff)
// fit within a 2byte utf8 char
// firstbyte = 110 +xxxxx := 0xc0 + (char>>6) MSB
// second    = 10 +xxxxxx := 0x80 + (char& 63) LSB
INC out$,  CHR$(bOR(0xc0, bAND(ASR(cha,6), 0x1f))) // 2+1+5 bits
INC out$,  CHR$(bOR(0x80, bAND(cha, 0x3f))) // 1+1+6 bits
ENDIF
NEXT

RETURN out$
ENDFUNCTION

INLINE
void Latin8FromUtf8(char* str, int slen) {
    int i = 0;

    char* dest = str;

    const char* pStrC = str;
    const char* pEnd = str + slen;
    // *pStrC != '\0' &&
    while(pStrC < pEnd) {
        const wchar_t c = wchar_t(static_cast<unsigned char>(*pStrC++));

        // U-0 to U-7F
        if((c & 0x80) == 0x00) {
            *dest++=char(c);
            continue;
        }
        // U-80 to U-7FF
        if((c & 0xE0) == 0xC0) {
            if(i<slen) {
                wchar_t d = static_cast<wchar_t>(*pStrC++);
                *dest++=(char((c&0x1f)<<6 | (d&0x3f)));
                continue;
            }
        }

        // U-800 to U-FFFF
        if((c & 0xF0) == 0xE0) {
            if(i+1<slen) {
                const wchar_t d = static_cast<wchar_t>(*pStrC++);
                const wchar_t e = static_cast<wchar_t>(*pStrC++);
                *dest++=(char((c&0x0f)<<12 | (d&0x3f)<<6 | (e&0x3f)));
                continue;
            }
        }
        // three continuation (U-10000 to U-10ffff)
        if((c & 0xF8) == 0xF0) {
            if(i+2<slen) {
                const wchar_t d = static_cast<wchar_t>(*pStrC++);
                const wchar_t e = static_cast<wchar_t>(*pStrC++);
                const wchar_t f = static_cast<wchar_t>(*pStrC++);
                *dest++=(char((((c&0x0f)<<18 | (d&0x3f)<<12 | (e&0x3f)<<6 | (f&0x3f)) + 655536)  & 0x000000ff));
                continue;
            }
        }
    }
    *dest = '\0';
}
ENDINLINE


//! Convert the utf8$ string to a Latin-1 (ISO 8895-1) string. Use this to 'PRINT' an UTF-8 string.
FUNCTION UTF8_toLatin1$: utf8$
LOCAL copy$ = utf8$
INLINE
char* str = copy_Str.getbuffer(1);
Latin8FromUtf8(str, LEN(copy_Str));
copy_Str.releasebuffer();
ENDINLINE
RETURN copy$

ENDFUNCTION


//! Return the 3 byte UTF-8 BOM (byte order mask).
//! That is the first 3 bytes of an UTF-8 text file.
FUNCTION UTF8_BOM$:
RETURN CHR$(0xef) + CHR$(0xbb) + CHR$(0xbf)
ENDFUNCTION

#14
Our webhoster quits. I have time to the end of 2019 to move to another hoster.
I amy very anxious about the email/https certificate after the move.
On the other hand, I can move to a hoster that cares about the linux backbone, so I don't have to care about this anymore. It caused my so much headache, since I'm a total noob when it comes to this.

Just wanted to let you know.
If anyone if good at that stuff, please let me know.
I would have to:
-move the php sites (easy)
-backup all email (4 accounts. I use thunderbird. I plan to pull them all local and then copy back. Would that be OK?)
-move 3 data bases (yes, this forum too!). I have no idea, but I hope something like mysql-php offers that option...
-point the domains (3) to the new server (I hope that one is a quick one. My new hoster offers a GUI for that).
-What about the certificate for the https/email accounts?
-Anything I missed?
#15
The version sounds like nothing special, but indeed, this update brings:
AUTOCOMPLETE for TYPE MEMBERS. (Ctrl+Space)
I took some time, yesterday and finally fixed what was due for years. I am so sorry for the delay. You will love it. It makes work so much easier, if you use TYPEs.

Also, DDgui was a bit polished and the new toast messages look quite good. (See my 2nd G.A.C.K. trailer on STEAM - sprite editor, where I copy/paste an image).
#16
https://store.steampowered.com/app/1117520/GACK__Gaming_App_Construction_Kit/

Wohoo! Finally made it to where it should go. I hope people will like it.
I added support for moving platforms. Did anyone program that before? Dude, that is really hard. I'm programming for about 0x20 years now, but that was a brain twister even for me. It's not 100.00% perfect after all...
#17
I remember yeeeers ago, someone had a bit of code, that created a random city. Houses and stuff.
Can anyone remember this?
It would be cool to make a "deliver a pizza" game in 3D, with a city like: C64's Miami Vice, but in 3D:
https://www.c64-wiki.de/wiki/Datei:mvmap.png

#18
The following is a C++ wrapper for a library, that does high-quality image scaling.
To use it, just add the gbas file to your project. The C++ lib is linked by REQUIRE.

Here's how to use it as a STRETCHSPRITE substitute:
Code (glbasic) Select

FUNCTION HQStretchSprite: id%, x%, y%, w%, h%
LOCAL s2% = GENSPRITE()
ReSampler(id, s2, w,h)
DRAWSPRITE s2, x,y
GRABSPRITE s2, 0,0,0,0
ENDFUNCTION

Warning - the above does not work (yet), if you're currently on an offscreen (USESCREEN x).
#19
Live on Steam as an update now :)
#20
In my store page I get the error:
The following localisations have not applied the new icon specification: English (United States).
Learn More

I can't change the text - what is wrong? Whatever I do with the icon - it won't let me pass.

Attached the icon I try to submit.