Jump to content

Programmering, kodning och/eller scripting


dibel
 Share

Recommended Posts

Tjena, tjena.

Det här kan vara tråden för generell programmering oavsett språk. Jag får ibland känsla för att koda lite och sätter igång med något projekt. Just nu är det lite scripting i GDScript (Godot 4) som gäller, men jag går i banorna att programmera lite i C (med biblioteken SDL2, Vulkan, SQLite, ImGUI, cgltf?) för att det är roligt. Man kan ju börja med att få standardkuben i Blender att rendereras och ta det därifrån.

Som alla vet är det Open Source-mjukvara och bibliotek som gäller för mig, särskillt när det gäller programmeringsprojekt. Bara man ser till att licensen är vad man anser vara okej (aktar sig för GPL om man inte avser att GPL:a sin egen kod m.m.) så är det bra.

Här är lite stats för C, C# och Javascript på min dator för en for loop som räknar till hundra miljoner:

C

Dölj innehåll
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <limits.h>

int main(int argc, char *argv[]) {
    for (int_fast32_t i = 0; i < 100000000; ++i) {
        printf("%"PRIu32"\n", i);
    }
    return 0;
}
[erik@erik-pc-01 iteration]$ time ./a.out &>/dev/null

real	0m3.302s
user	0m3.278s
sys	0m0.020s

 

C#

Dölj innehåll
for (int i = 0; i < 100000000; ++i) {
    Console.WriteLine(i);
}
[erik@erik-pc-01 Iteration]$ time bin/Release/net8.0/Iteration &>/dev/null

real	0m54.805s
user	0m28.733s
sys	0m26.001s

 

Javascript

Dölj innehåll
for (let i = 0; i < 100000000; i++) {
    console.log(i)
}
[erik@erik-pc-01 iteration]$ time node index.js &>/dev/null

real	2m23.249s
user	2m3.020s
sys	0m20.286s

 

Ignorera parametern &>/dev/null som bara betyder att omdirigera stdout till "ingenting" för att undvika att benchmarka terminalen/konsolen istället för koden.

Som ni ser är C King of Kings. C# fastnar i runtime (dotnet) alldeles för länge i Systemet innan själva koden körs och Javascript som simplast och dynamiskt typat tar väldigt mycket längre tid.

C-programmet är kompilerat i gcc 14.1.1 med -O3

C#-programmet är gjort med dotnet därför ser det så simpelt ut utan någon class och "main"-funktion. Enligt Microsofts Hello World-exempel som man får när man gör ett nytt projekt i dotnet.

Javascriptet körs i NodeJS 22.4.1.

Efter denna simpla benchmark är jag ganska besviken på dotnet/C# faktiskt. Visst, lite overhead med runtime får man räkna med, men att den är så stor var en negativ överraskning.

---

Nå, hur ser era programmeringsvanor ut? Studier, projekt m.m. kan tas i tråden.

HH (Happy Hacking)!

Redigerad av dibel
  • Gilla 1
Länk till kommentar
Dela på andra sidor

Det här är fortfarande min största bedrift och jag installerar det på alla jobbdatorer jag har eftersom de för det mesta saknar en hibernation-knapp. Men Ctrl-Alt-V för viloläge och sen denna prompt så är den släckt på direkten. Vill säga, om man bara trycker enter utan att trycka in någon tid så blir det automatiskt noll = nu.

2015-04-14 at 13:15, Henkibojj skrev:

Igår lärde jag mig lite nya kommandon i CMD, eller .bat-filer. Jag har sedan tidigare förstått mig på datoravstängningskommandot shutdown och timertillägget /t 300 vilket ger en fördröjning på 300 sekunder = 5 minuter. Med detta gjorde jag år 2011 en massa smarta entimmes-, tvåtimmars- och liknande timers, inklusive en avbrytar-bat.

Men jag har alltid saknat en /t för Viloläge: shutdown /h, för kommandot shutdown /h /t 300 existerar inte i CMD. Det har alltså varit omöjligt att göra en timer för vanligt viloläge. Poängen med viloläge är mest att jag ofta vill ha kvar de program jag har igång utan att göra en cold shutdown.

Igår lärde jag mig kommandot TIMEOUT /NOBREAK 300 för 300 sekunders väntan inför nästa kodrad, samt hur man sätter egna värden (dvs inte CHOICE) genom set /p siffervaerde. Man kan dessutom manipulera siffervaerde med den aritmetiska operatorn /a, vilket ger möjlighet att sätta siffervaerde+-*/ ett annat värde, till exempel 60 för att göra om minuter till sekunder. Vill man referera till värdet skriver man %siffervaerde%.

Som bonus lärde jag mig det väldigt enkla kommandot time /t för att visa klockan.

Resultatet var en betydligt smidigare och många gånger bättre batfil än de ~7 standardtider jag knåpade ihop 2011.

Kolla in och spara gärna ned på egen hårddisk för sena Netflix-kvällar i sängen med datorn på storbild! :)

 @echo off

:start

cls

echo Välj V för viloläge.

echo Välj A för avstängning.

echo Välj X för att avbryta.

choice /c:VAX

if errorlevel 3 goto Avbryt

if errorlevel 2 goto Shutdn

if errorlevel 1 goto Sleeping

:Avbryt

echo.

echo Jaså, då säger vi hejdå.

pause

goto end

:Shutdn

echo.

echo VARNING! Du har valt avstängning. Alla program kommer att stängas ned utan sparning vid timerns slut. Är du säker på att du vill fortsätta?

choice /c:jn

if errorlevel 2 goto start

cls

echo Om hur lång tid ska datorn stängas av?

set /p minuter="Tid i minuter: "

set /a sekunder=%minuter%*60

echo.

echo Timern har satts till %minuter% minuter = %sekunder% sekunder. Klockan är nu

echo.

TIME /t

echo ...och datorn kommer att stängas av efter följande tid. Se till att spara allt arbete!

TIMEOUT /NOBREAK %sekunder%

shutdown /f

goto end

:Sleeping

echo.

echo Om hur lång tid ska datorn försättas i viloläge?

set /p minuter="Tid i minuter: "

set /a sekunder=%minuter%*60

echo.

echo Timern har satts till %minuter% minuter = %sekunder% sekunder. Klockan är nu

echo.

TIME /t

echo ...och datorn kommer att försätts i viloläge efter följande tid:

TIMEOUT /NOBREAK %sekunder%

shutdown /h

:end

 

Och skratta inte åt mig, jag har aldrig programmerat något annat än BAT :unsure: Python under fem veckor på en obegriplig Unix-dator i gymnasiet tycker jag inte räknas.

 

Lite länkar:

http://www.robvanderwoude.com/wait.php

http://commandwindows.com/variables.htm

 

Tjing pling! :)

/1337

  • Gilla 1
Länk till kommentar
Dela på andra sidor

7 timmar sedan, Henkibojj skrev:

Det här är fortfarande min största bedrift och jag installerar det på alla jobbdatorer jag har eftersom de för det mesta saknar en hibernation-knapp. Men Ctrl-Alt-V för viloläge och sen denna prompt så är den släckt på direkten. Vill säga, om man bara trycker enter utan att trycka in någon tid så blir det automatiskt noll = nu.

/1337

Funkar det så funkar det. Hur blir det vid input vid choices? Om man skriver "gtasajten" när den vill ha V, A eller X t.ex.?

Knåpade ihop ett powershell-script baserat på ditt batch-script:

Dölj innehåll
Function get_user_input {
	return Read-Host "Choice"
}

Function w {
	Param
	(
		[Parameter(Mandatory=$true, Position=0)]
		[string] $msg
	)
	Write-Host $msg
	return
}

Function get_choice {
	$ret = "x"
	$choices = @{
		v="Hibernate";
		a="Shutdown";
		x="Cancel"
	}
	$continue = $true
	while ($continue) {
		foreach ($hash in $choices.GetEnumerator()) {
			w -msg "Choose $($hash.name) to $($hash.value)"
		}
		$p = get_user_input
		Switch -Regex ($p) {
			"^[Vv].*" {
				$ret = "v"
				$continue = $false
			}
			"^[Aa].*" {
				$ret = "a"
				$continue = $false
			}
			"^[Xx].*" {
				$ret = "x"
				$continue = $false
			}
			Default {
				w -msg "Fail"
			}
		}
	}
	return $ret
}

Function get_y_or_n {
	$ret = "default"
	$continue = $true
	while ($continue) {
		$p = get_user_input
		Switch -Regex ($p) {
			"^[Yy]|[Jj].*" {
				$ret = "y"
				$continue = $false
			}
			"^[Nn].*" {
				$ret = "n"
				$continue = $false
			}
			Default {
				w -msg "Fail"
			}
		}
	}
	return $ret
}

Function shutdown_or_hibernate {
	Param
	(
		[Parameter(Mandatory=$true, Position=0)]
		[string] $m
	)
	$timeout = get_timeout
	w -msg $timeout
	Get-Date
	Switch -Regex ($m) {
		"^v" {
			Timeout /NoBreak $timeout
			#Shutdown /h
			w -msg "Shutdown /h"
			
		}
		"^a" {
			Timeout /NoBreak $timeout
			#Shutdown /f
			w -msg "Shutdown /f"
		}
	}
}

Function get_timeout {
	$ret = 0
	$continue = $true
	while ($continue) {
		w -msg "Enter minutes (integer)"
		$p = get_user_input
		$i = $p -as [int]
		if ($i -is [int]) {
			$ret = $i
			$continue = $false
		}
		else {
			w -msg "$($p) is not an integer"
		}
	}
	return $ret * 60
}

$mode = get_choice

if ($mode -eq "x") {
	exit
}

shutdown_or_hibernate -m $mode

 

Vet inte om det är till någon nytta, men lite kul att koda sitt första PS-script åtminstone. Körde Windows 10 i en VM och den verkar funka (om man tar bort # som är en kommentar för själva shutdown-kommandona på de 2 ställena).

Funktionen w är helt onödig, men jag gjorde den som en helper för att slippa skriva Write-Host hela tiden, hehe. Trodde man skulle kunna köra w("string"), men i PS så är parametrar en flagga man lägger till.

Kopiera och ändra strängarna till svenska och lägg till och ändra hur mycket du vill. Public Domain License, haha.

Funktionaliteten att avsluta med X är dock helt onödig då man alltid kan avsluta med Ctrl-C i terminalen (vet inte hur det är i cmd.exe dock).

Nåväl, kul miniprojekt.

Länk till kommentar
Dela på andra sidor

  • 2 weeks later...
  • 3 weeks later...

Är inte speciellt komfortabel med några riktiga språk förutom Powershell, men det behärskar jag bra! Det blir lätt så när det är enda sättet att automatisera bort jobbiga jävla arbetsuppgifter. Min arbetsgivare är för snål för att köpa ett HRIS-system som kan integreras mot Active Directory, så fram tills jag började förra året satt en stackare på IT och skapade användarkonton manuellt. Tror det är 10-15 nya som börjar varje månad, så det är ett väldigt tradig arbete till slut. Alla anställda jobbar hemifrån också, så det var en jobbig manuell process. Det blir som upplagt för en bokstav fel här och där när man sitter och kopierar och klistrar mellan olika fönster, samt att att kommunicera lösenord.

Nu går det till såhär istället:

  1. Chefen för den nyanställda matar in en beställning i Jira.
  2. Jira kickar igång en Logic App på Azure
  3. Logic Appen kör ett Powershell-skript för att generera ett lösenord från en ordlista. Cirka 5000 ord. Lösenorden som kommer ut är typ "Glassmaskin bildäck?"
  4. Ett nytt Powershell-skript med inputten från Jira samt lösenordet från steg 3.
  5. Den kontrollerar om allting gick bra - om nej så kommenterar det i Jira-ärendet. Oftast är det skit bakom spakarna, men ibland kommer det in sådant som det är enkelt att lösa i skriptet i sig, och då gör jag det såklart. Som kodsnutten nedan t.ex. Vi fick in en nyanställd med ett väldigt långt efternamn, så den översteg maxgränsen på SamAccountName-attributet, så då fick jag lägga till det här för att det inte ska hända igen, t.ex
     
    if ($email.Length -gt 20) {
        $samaccountname = $email.Substring(0, 20)
    } else {
        $samaccountname = $email
    }
  6. Om det gick bra så går den vidare med att skicka ett välkomstbrev med användarnamn och lösenord till användarens privata e-postadress. Krypterat och tjusigt! Fick kämpa mot vår CISO länge innan han godkände det istället för att vi skulle skriva ut det på papper och skicka hem fysiskt.

    image.png.534aa93302c2d48b393318e69303dca4.png

  Kan inte dela något av skriptet som skapar användaren, det är för mycket som är specifikt till vår miljö, men i grund och botten är det bara New-ADUser, parametrarna som kom med Jira, samt en herrans massa grupptilldelningar som har lite olik logik beroende på anställningsort, närmsta chef, yrkesroll, etc.

Det jag arbetat med senast är att sätta inaktiveringsdatum på användare direkt från Jira också. Där frågar jag bara efter datumet som kontot ska inaktiveras, samt mejladressen till användaren. Eftersom vi har en sådan jävla ruljans på folk (som 10-15 nya per månad skvallrar om) så är det såklart många som måste inaktiveras också. Detta sätter inaktiveringsdatumet till det valda datumet. Om det datumet redan har passerats så inaktiveras kontot på en gång.

Nu måste jag bara kontakta vår CISO igen och försöka övertyga människan om att jag ska få sätta upp något schemalagt jobb som tar bort användare som har varit inaktiverade i mer än 6 månader varje natt... heja.
 

Redigerad av Gof
  • Gilla 1
  • Tack! 1
Länk till kommentar
Dela på andra sidor

Jag hade faktiskt inte ens hört talas om PowerShell förrän chefen hos min kund plockade in sommarjobbare som använde det till att automatisera namnhantering på bulkskannade dokument. Det låter som att mycket av det jag gör manuellt på heltid skulle kunna prova försiktiga små steg i PS, men jag är å andra sidan anlitad för att hålla på med saker där nästan allt som görs är undantag från normen, vilket är varför jag inte använt mig av klickmakron ens. Dock makron i W0rd, men bara för att snabba på det redan alltför manuella jobbet.

Länk till kommentar
Dela på andra sidor

2024-08-19 at 12:38, Henkibojj skrev:

Jag hade faktiskt inte ens hört talas om PowerShell förrän chefen hos min kund plockade in sommarjobbare som använde det till att automatisera namnhantering på bulkskannade dokument. Det låter som att mycket av det jag gör manuellt på heltid skulle kunna prova försiktiga små steg i PS, men jag är å andra sidan anlitad för att hålla på med saker där nästan allt som görs är undantag från normen, vilket är varför jag inte använt mig av klickmakron ens. Dock makron i W0rd, men bara för att snabba på det redan alltför manuella jobbet.

Skapa en kopia på ett av dina arbetsdokument och testa! Beroende på din arbetsplats så kan Powershell vara ganska nedlåst om du inte har adminaccess, men det går att påverka det mesta i en Windows-miljö.

Länk till kommentar
Dela på andra sidor

Får man räkna sånt man skapar med AI som sitt eget, förresten? I sådanafall kan jag stoltsera med den här dunderhemsidan: https://tyrannosaurus.se

Bakgrunden är jättesimpel - våra nyanställda tyckte det var så svårt att komma på egna lösenord, samt att förstå lösenordskraven. Internt har jag en funktion där dom loggar in med sitt Microsoft-konto så den tar namnet därifrån, men det kändes olämpligt att publicera, så alla (hela 83 någonsin!) besökare till den publika biten får fylla i sitt namn på egen hand.



 

Länk till kommentar
Dela på andra sidor

  • 5 months later...
2024-08-21 at 13:45, Gof skrev:

Får man räkna sånt man skapar med AI som sitt eget, förresten? I sådanafall kan jag stoltsera med den här dunderhemsidan: https://tyrannosaurus.se

Bakgrunden är jättesimpel - våra nyanställda tyckte det var så svårt att komma på egna lösenord, samt att förstå lösenordskraven. Internt har jag en funktion där dom loggar in med sitt Microsoft-konto så den tar namnet därifrån, men det kändes olämpligt att publicera, så alla (hela 83 någonsin!) besökare till den publika biten får fylla i sitt namn på egen hand.



 

Det tycker jag räknas, absolut. Snygg sida!

---

Gjorde 100-miljoners testet i Java (openjdk 23.0.2 2025-01-21) och Lua (Lua 5.4.7), här är resultaten:

[erik@erik-pc-01 lua]$ time lua main.lua &>/dev/null 

real	0m37.042s
user	0m24.895s
sys	0m12.056s
[erik@erik-pc-01 java]$ time java Test &>/dev/null 

real	0m34.082s
user	0m19.561s
sys	0m14.828s

Java slår C# och Lua fullständigt krossar Javascript och springer jämsides med Java. Mest imponerad av Lua faktiskt som är ett dynamiskt typat språk. Inte konstigt att många spelutvecklare använde(r) Lua som scriptspråk för ai och moddning.

Nästa testinlägg får väl bli Python och Rust eller något, hehe. Ska ju nämnas att det är ett väldigt simpelt test, en jävla for-loop liksom, men ändå. Säger något om prestandan att räkna till 100 miljoner och printa ut varje enskilt tal.

Länk till kommentar
Dela på andra sidor

  • 2 weeks later...

Hittade en enligt mig bra kommentar på "Hacker News":

Citera
Yes, but it's also thanks to this mentality that a simple text editor occupies 1 gig of ram and two cpu cores nowadays. If the dev's machine is infinitely fast and has storage as fast as other people's ram, they stop caring about performance issues, because they never encounter them in the first place. And I'm not talking about working on hand written assembly for a week to get the last bit of performance. I've repeatedly found silly things like O(n) code calculating something that could be expressed as O(1), hilariously complicated xpath expressions that in the end just retrieved an immediate child and whatnot.

At one of my first jobs, when my boss got annoyed by some software being slow, je always said that developers should get the fastest hardware available, but as soon as they start testing or using their own software, the machine needs to magically turn into a 386 with your home directory on an NFS share. Granted, that was 20 years ago so 386 didn't sound as hilarious as it does now, but it was still a little extreme. But that idea stuck with me, and to this day I do test software on slow machines every now and then, looking for obvious performance left on the table.

https://news.ycombinator.com/item?id=27796443

Jag förstår bara hälften, vet inte skillnaden mellan O(n) och O(1), men Bossen som ville testa på 386:or med /home på en NFS-share hade helt rätt mentalitet.

Istället får vi Electron-produkter och spelgrafiken har inte utvecklats på 10 år. Alla nya spel ser ut som ett moddat Skyrim med 4K-texturer. De här nya teknologierna med upskalning istället för native tror jag inte heller på.

Langa texturer för 8K (High), 4K (Medium) och 1080p (Low). Ultra får väl vara 8K med AA?

Man kör upp till Ultra och så är det Javascript-kod som skalar upp 720p-texturer till 4K, hehe.

Gamers, arise!

Redigerad av dibel
Länk till kommentar
Dela på andra sidor

29 minuter sedan, dibel skrev:

Hittade en enligt mig bra kommentar på "Hacker News":

https://news.ycombinator.com/item?id=27796443

Jag förstår bara hälften, vet inte skillnaden mellan O(n) och O(1), men Bossen som ville testa på 386:or med /home på en NFS-share hade helt rätt mentalitet.

Istället får vi Electron-produkter och spelgrafiken har inte utvecklats på 10 år. Alla nya spel ser ut som ett moddat Skyrim med 4K-texturer. De här nya teknologierna med upskalning istället för native tror jag inte heller på.

Langa texturer för 8K (High), 4K (Medium) och 1080p (Low). Ultra får väl vara 8K med AA?

Man kör upp till Ultra och så är det Javascript-kod som skalar upp 720p-texturer till 4K, hehe.

Gamers, arise!

Det är för mycket lingo för mig, men principen stämmer. Man bör ha de bästa studiohögtalarna som finns att köpa på specialmarknaden när man producerar musik, men för att verkligen veta vad det är som når publiken bör man sedan exportera det till riktiga skitsystem och hitta en balans för vad som låter bra i studio, vad som låter bra i dessa jävla airpods, vad som låter bra på en hemmastereo och vad som låter bra på ett någotsånär bra hemmasystem.

Anledningen att Roxette låter som de gör med mycket mid-gitarr, tanig virveltrumma och plonkig istället för djup elbas, är att de visste att merparten av lyssnarna får höra det antingen på radio eller på kassett i boomboxar. Och då menar jag inte såna som stekare köpt från Bose (som för övrigt har för stark bas i fanimig alla sina system) med Bluetooth, utan såna med fysiska spakar och rattar och utfällbar antenn från 1988-1993. Och det låter jäkla bra.

Länk till kommentar
Dela på andra sidor

2 timmar sedan, Henkibojj skrev:

Det är för mycket lingo för mig, men principen stämmer. Man bör ha de bästa studiohögtalarna som finns att köpa på specialmarknaden när man producerar musik, men för att verkligen veta vad det är som når publiken bör man sedan exportera det till riktiga skitsystem och hitta en balans för vad som låter bra i studio, vad som låter bra i dessa jävla airpods, vad som låter bra på en hemmastereo och vad som låter bra på ett någotsånär bra hemmasystem.

Anledningen att Roxette låter som de gör med mycket mid-gitarr, tanig virveltrumma och plonkig istället för djup elbas, är att de visste att merparten av lyssnarna får höra det antingen på radio eller på kassett i boomboxar. Och då menar jag inte såna som stekare köpt från Bose (som för övrigt har för stark bas i fanimig alla sina system) med Bluetooth, utan såna med fysiska spakar och rattar och utfällbar antenn från 1988-1993. Och det låter jäkla bra.

Ja det är lingo, samma med spakar och antenner och radiomastar, hehe. Olika branscher helt enkelt.

Fun fact, det var inte alltför länge sedan 32-bitars Linux bytte från i386 (1985-teknologi) till i686 (1995-teknologi). När jag började med GNU/Linux 2008 så fanns Debian i båda versioner (och amd64, i.e. 2003-teknologi som vi lite har fastnat i, som jag körde då jag hade en C2D). Var man riktigt imba körde man PAE-aktiverad kernel om man var fast på en Pentium 4 utan 64-bitars stöd.

Lite off-topic, men jag tar det här istället för att ranta i Linuxtråden. Det var bättre förr, eller inte kanske. :D

Länk till kommentar
Dela på andra sidor

Eftersom jag inte vågar bumpa Skyrim-tråden så tar jag det här.

Fortsättning på tidigare spaning av grafik, högupplösta texturer, effekter m.m.

Jag har forskat lite (hehe) och kommit fram till att DDS-containern Skyrim Special Edition (64-bit kompatibel jmf med Legendary Edition, numera finns även Anniversary Edition som är SE, men med lite CC-content tillagt tror jag) har texturer komprimerade med BC7-standard, vilket tyvärr inget open source-alternativ verkar stödja (än så länge, GIMP jobbar på import åtminstone) så jag går i tankarna att börja laborera med detta.

Dvs öppna en .dds, extrahera texture för att sedan skala upp med ESRGAN (typ, antagligen en modifierad/modern modell) för att behålla äktheten, men få det i native 4K.

Jag är inte så mycket för total conversions som exemplet till höger visar, även om det ser snyggt ut (Tillägg: Eller nja, det finns snyggare, men ändå). På så vis skulle man få en 4K-native Skyrim (högre krav på VRAM m.m.) medan man behåller originalstilen så som Skyrim ska upplevas.

Exempel taget från reddit visar på möjligheten:

https://imgur.com/s8yhruO

Om jag lyckas med detta, där .dds och BC7 är det stora kruxet, kan man med enkelhet scripta extrahering och upskalning med exempelvis bash eller python för att batch-uppskala hela Skyrim Special Edition (4x siktar jag på som är standarden på uppskalar-modellerna). Är man petnoga så gör man det för hand, men en ren 4x-uppskalning kan vara en god grund att börja med om det inte tär alltför mycket på VRAM (jag har en del på min arbetsstation åtminstone).

Och ja, jag tänker skriva skiten i C, hehe. Första steget är väl att smygkika på GIMP:s implementering av BC7-importer och se hur de gör.

Tjohej.

Tillägg: Vet inte vad som hände med texten, men men.

Tillägg 2: Här finns en lite mer sajtaktuell (GTA3-generationens .img-filer) på den process/workflow jag hade tänkt mig: https://github.com/antarktikali/gta3-img-builder

Jag kanske ska börja med att skala upp GTA 3 med detta verktyg för att utöka scriptkunskaperna först, hehe.

Jag kan ju förstås inte publicera slutprodukten (texturer uppskalade av copyrightade filer) utan det är ju endast för eget bruk, men verktygen för att hantera .dds/BC7 eller i GTA 3:s fall .img-filer kan man ju publicera / opensourca.

Tillägg 3: Detta ser intressant ut för att hantera .dff och .txd som ingår i gta3.img: https://github.com/Parik27/DragonFF

Är lite mosig just nu, men man kan säkert scripta upp gta3-img-builder > DragonFF > ESRGAN > DragonFF > gta3-img-builder, åtminstone för själva texturerna. Sedan måste man väl hålla på med normals och UV mappning m.m. (i Blender), men det är grunden på workflow med detta (open source) toolset.

Bered er på en äkta 4K upplevelse av GTA3(VC/SA) istället för Definitive Edition som verkar suga?

Redigerad av dibel
Länk till kommentar
Dela på andra sidor

  • 1 year later...
2025-02-05 at 21:03, dibel skrev:

Det tycker jag räknas, absolut. Snygg sida!

---

Gjorde 100-miljoners testet i Java (openjdk 23.0.2 2025-01-21) och Lua (Lua 5.4.7), här är resultaten:

[erik@erik-pc-01 lua]$ time lua main.lua &>/dev/null 

real	0m37.042s
user	0m24.895s
sys	0m12.056s
[erik@erik-pc-01 java]$ time java Test &>/dev/null 

real	0m34.082s
user	0m19.561s
sys	0m14.828s

Java slår C# och Lua fullständigt krossar Javascript och springer jämsides med Java. Mest imponerad av Lua faktiskt som är ett dynamiskt typat språk. Inte konstigt att många spelutvecklare använde(r) Lua som scriptspråk för ai och moddning.

Nästa testinlägg får väl bli Python och Rust eller något, hehe. Ska ju nämnas att det är ett väldigt simpelt test, en jävla for-loop liksom, men ändå. Säger något om prestandan att räkna till 100 miljoner och printa ut varje enskilt tal.

Jag vet inte om du redan gjort testet, men om du inte gjort det kan jag ge en liten hint om hastighetsskillanderna mellan Python och C.

Jag testade nyligen hur pass bra en specifik rensningsmetod faktiskt rensade hårddiskar. En hårddisk som jag fyllde med data, och sedan läste genom efteråt resulterade i en strax över 170GB stor binär fil innehållandes alla index ranges där data hittats.

Efteråt lät jag ett Pythonscript bränna genom alla index för att skapa en vettig statistik över datan, det tog lite över 70 dagar, 75 eller 77 om jag minns rätt.

Jag konverterade för skojs skull scriptet till C och lät den läsa genom filen. Den var klar på strax över tre minuter.

 

Med det sagt beror det såklart oerhört mycket på vad koden ska göra, vissa saker skiljer inte alls lika mycket, medan andra kan skilja än mer i hastighet.

Länk till kommentar
Dela på andra sidor

16 timmar sedan, eXotic skrev:

Jag vet inte om du redan gjort testet, men om du inte gjort det kan jag ge en liten hint om hastighetsskillanderna mellan Python och C.

Jag testade nyligen hur pass bra en specifik rensningsmetod faktiskt rensade hårddiskar. En hårddisk som jag fyllde med data, och sedan läste genom efteråt resulterade i en strax över 170GB stor binär fil innehållandes alla index ranges där data hittats.

Efteråt lät jag ett Pythonscript bränna genom alla index för att skapa en vettig statistik över datan, det tog lite över 70 dagar, 75 eller 77 om jag minns rätt.

Jag konverterade för skojs skull scriptet till C och lät den läsa genom filen. Den var klar på strax över tre minuter.

 

Med det sagt beror det såklart oerhört mycket på vad koden ska göra, vissa saker skiljer inte alls lika mycket, medan andra kan skilja än mer i hastighet.

Ja, det är ju så med script och programmeringsspråk. Det snyggaste i ditt fall hade varit att göra ett C-bibliotek eller så som du sen bara kallar på med Pythonscriptet eller liknande? Kanske förlust på 0.01% prestanda med "pythonic" (med C i bakgrunden) enkelhet?

Klart att Python är "nice" ibland, särskillt som AI modeller och liknande använder det, men i bakgrunden är det ju CUDA och ROCm eller liknande som används och de kör ju GPGPU på grafikkkortet om jag inte har helt fel.

Som en liten anekdot kan jag ju droppa någon nisse som på sin arbetsintervju skulle "lösa ut" något lösenord eller liknande från en textfil... Medan alla andra jobbade semi-komplicerade lösningar i programmeringsspråk eller scripting så körde han bara bash-script med awk på filen och hans skillz gjorde att han fick jobbet gjort på (IRL-tid) 5 sekunder medan de andra ansökande satt i flera timmar för att klura ut filen (hur det nu än var)...

Rätt man på rätt plats, eller i det här fallet - Rätt programmeringsspråk för rätt tillfälle. :innocent:

---

I övrigt har jag ett RPG projekt i HTML/CSS/JS med över 3 tusen rader kod (3.3K LOC, gammal version), skriven med hjälp av AI (Google AI, inte Gemini)... Det var sommar-projektet i år, får se om man tar upp det igen. Jävligt fint kodat med bitwise-operationer m.m. som man kan göra i JavaScript dessutom (som ett sätt att packetera booleans etc.), vilket var kul att göra igen.

Som en transition från IRL till forumet, skål för Sabaton och Bajen, hehe. Ser fram emot att ta upp projektet igen, då det var ett intressant arbetssätt (Google AI + självlärd kunskap) för att få fram ett fullt fungerande och operativt system.

Full, funktionell och operation, Anakin. :ph34r:

Länk till kommentar
Dela på andra sidor

2026-08-24 at 14:49, dibel skrev:

Ja, det är ju så med script och programmeringsspråk. Det snyggaste i ditt fall hade varit att göra ett C-bibliotek eller så som du sen bara kallar på med Pythonscriptet eller liknande? Kanske förlust på 0.01% prestanda med "pythonic" (med C i bakgrunden) enkelhet?

Klart att Python är "nice" ibland, särskillt som AI modeller och liknande använder det, men i bakgrunden är det ju CUDA och ROCm eller liknande som används och de kör ju GPGPU på grafikkkortet om jag inte har helt fel.

Som en liten anekdot kan jag ju droppa någon nisse som på sin arbetsintervju skulle "lösa ut" något lösenord eller liknande från en textfil... Medan alla andra jobbade semi-komplicerade lösningar i programmeringsspråk eller scripting så körde han bara bash-script med awk på filen och hans skillz gjorde att han fick jobbet gjort på (IRL-tid) 5 sekunder medan de andra ansökande satt i flera timmar för att klura ut filen (hur det nu än var)...

Rätt man på rätt plats, eller i det här fallet - Rätt programmeringsspråk för rätt tillfälle. :innocent:

---

I övrigt har jag ett RPG projekt i HTML/CSS/JS med över 3 tusen rader kod (3.3K LOC, gammal version), skriven med hjälp av AI (Google AI, inte Gemini)... Det var sommar-projektet i år, får se om man tar upp det igen. Jävligt fint kodat med bitwise-operationer m.m. som man kan göra i JavaScript dessutom (som ett sätt att packetera booleans etc.), vilket var kul att göra igen.

Som en transition från IRL till forumet, skål för Sabaton och Bajen, hehe. Ser fram emot att ta upp projektet igen, då det var ett intressant arbetssätt (Google AI + självlärd kunskap) för att få fram ett fullt fungerande och operativt system.

Full, funktionell och operation, Anakin. :ph34r:

Det är helt klart ett alternativ, många Pythonpaket är skrivna i C!
Men det här var en engångsgrej, generellt sett har vi inte några prestandakrav på det vi bygger, att jag hackade ihop samma script fast i C var mest för skojs skull. :D

Däremot så använder vi generellt Python för våra script då det först och främst är ett språk som alla i teamet kan, det går snabbt att skriva ihop de script och automationer vi ska bygga, det är lätt att felsöka och underhålla, och slutligen så är det lätt att lära sig. Så om vi tar in en ny i teamet är det inte hela världen om denne inte kan just Python, det går ganska lätt att lära ut.
Även om jag skulle kunna skriva de tungdrivna grejerna vi gör återkommande i C för att få ett snärtigare program, så skulle det snabbt bli kalabalik om någonting skiter sig när jag inte är på plats i och med att C-kunskapen är väldigt låg hos mina kollegor.

Med det sagt så gör vi fler och fler webapplikationer då vi utvecklar saker som kräver användarintegration, till skillnad mot våra gamla grejer som mest tuffade på i bakgrunden. Då kör vi frontend med React, backend har hittills mest blivit Flask (Python) men jag är sugen på att testa någon JS-baserad backend för att skära ned på mängden språk i samma projekt. Just Javascript hanterar de flesta i teamet relativt väl så det borde inte vara omöjligt att få köra på. :P 

Länk till kommentar
Dela på andra sidor

Jaani grabbar ni kan hållas med ert. Själv skrev jag ett program för Ti-83 häromdagen som kommer hjälpa mig hålla mina batterier laddade med solceller. Ja, inte fysiskt då, men det blir lättare att minnas vad jag lämnade dem på och hur lång tid det kommer ta att ladda upp dem med vad jag bedömer att vädret kommer att erbjuda.

Och Ti-83:an ifråga vet jag inte ens var jag har nånstans, det är en emulator på mobilen jag har.

ti-83.jpg

Länk till kommentar
Dela på andra sidor

Bara som en grej jag gjorde nu, av anledningar, är en humanoid 3D modell i Blender (5.2.0 LTS) med hjälp av ChatGPT och Python script.

Här är hela Python scriptet (AI genererat) som man sedan laddar in i Blender;

Dölj innehåll
import bpy
import math
from mathutils import Vector

# ============================================================
# PROCEDURAL HUMANOID BASE MESH
# Blender 5.2.x
#
# Creates a generic adult humanoid base mesh with:
# - bilateral symmetry
# - head, torso, pelvis
# - arms, hands, legs, feet
# - smooth transitions
# - final unified/remeshed mesh
#
# No external modules required.
# ============================================================

# ------------------------------------------------------------
# SETTINGS
# ------------------------------------------------------------

BODY_NAME = "Humanoid_Base"

# Overall height
HEIGHT = 1.80

# Voxel size for final remesh.
# Smaller = more detail / slower.
VOXEL_SIZE = 0.035

# Subdivision level after remeshing
SUBDIVISION_LEVELS = 1

# Smooth iterations
SMOOTH_FACTOR = 0.65

# Keep generated object selected
SELECT_RESULT = True


# ------------------------------------------------------------
# BASIC UTILITIES
# ------------------------------------------------------------

def clear_scene():
    """Remove all existing objects."""
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=False)

    # Remove orphaned meshes/materials if possible
    for datablocks in (
        bpy.data.meshes,
        bpy.data.curves,
        bpy.data.materials,
    ):
        for block in list(datablocks):
            if block.users == 0:
                datablocks.remove(block)


def add_uv_sphere(name, location, scale):
    """Create a UV sphere and scale it."""
    bpy.ops.mesh.primitive_uv_sphere_add(
        segments=32,
        ring_count=20,
        location=location
    )

    obj = bpy.context.object
    obj.name = name
    obj.scale = scale

    bpy.ops.object.transform_apply(
        location=False,
        rotation=False,
        scale=True
    )

    return obj


def add_cylinder_between(name, p1, p2, radius1, radius2=None):
    """
    Create a tapered cylinder between two points.
    """
    if radius2 is None:
        radius2 = radius1

    p1 = Vector(p1)
    p2 = Vector(p2)

    direction = p2 - p1
    length = direction.length

    if length == 0:
        return None

    midpoint = (p1 + p2) * 0.5

    bpy.ops.mesh.primitive_cone_add(
        vertices=32,
        radius1=radius1,
        radius2=radius2,
        depth=length,
        location=midpoint
    )

    obj = bpy.context.object
    obj.name = name

    # Blender cone local Z axis -> direction
    obj.rotation_mode = 'QUATERNION'
    obj.rotation_quaternion = direction.to_track_quat('Z', 'Y')

    bpy.ops.object.transform_apply(
        location=False,
        rotation=False,
        scale=True
    )

    return obj


def add_capsule_segment(name, p1, p2, radius1, radius2=None):
    """
    Approximate a rounded body segment with:
    - tapered cylinder
    - sphere at each end

    The final voxel remesh merges these volumes.
    """
    if radius2 is None:
        radius2 = radius1

    objects = []

    cylinder = add_cylinder_between(
        name + "_Segment",
        p1,
        p2,
        radius1,
        radius2
    )

    if cylinder:
        objects.append(cylinder)

    objects.append(
        add_uv_sphere(
            name + "_EndA",
            p1,
            (radius1, radius1, radius1)
        )
    )

    objects.append(
        add_uv_sphere(
            name + "_EndB",
            p2,
            (radius2, radius2, radius2)
        )
    )

    return objects


def add_joint(name, location, radius):
    """Add a rounded joint volume."""
    return add_uv_sphere(
        name,
        location,
        (radius, radius, radius)
    )


# ------------------------------------------------------------
# BODY GENERATION
# ------------------------------------------------------------

def build_humanoid():
    parts = []

    # ========================================================
    # CENTRAL BODY
    # ========================================================

    # Pelvis
    parts.append(
        add_uv_sphere(
            "Pelvis",
            (0.0, 0.0, 0.93),
            (0.31, 0.20, 0.25)
        )
    )

    # Lower abdomen
    parts.append(
        add_uv_sphere(
            "Lower_Abdomen",
            (0.0, 0.0, 1.12),
            (0.28, 0.18, 0.27)
        )
    )

    # Abdomen
    parts.append(
        add_uv_sphere(
            "Abdomen",
            (0.0, 0.0, 1.32),
            (0.30, 0.19, 0.29)
        )
    )

    # Ribcage
    parts.append(
        add_uv_sphere(
            "Ribcage",
            (0.0, 0.0, 1.48),
            (0.37, 0.21, 0.34)
        )
    )

    # Upper chest
    parts.append(
        add_uv_sphere(
            "Upper_Chest",
            (0.0, 0.0, 1.59),
            (0.35, 0.20, 0.25)
        )
    )

    # Neck
    parts.extend(
        add_capsule_segment(
            "Neck",
            (0.0, 0.0, 1.62),
            (0.0, 0.0, 1.75),
            0.105,
            0.115
        )
    )

    # Head
    parts.append(
        add_uv_sphere(
            "Head",
            (0.0, 0.0, 1.89),
            (0.19, 0.17, 0.235)
        )
    )

    # Slightly broaden back of skull
    parts.append(
        add_uv_sphere(
            "Skull_Back",
            (0.0, 0.035, 1.89),
            (0.18, 0.15, 0.21)
        )
    )

    # ========================================================
    # SHOULDERS + ARMS
    # ========================================================

    for side in (-1, 1):

        s = float(side)

        shoulder = (0.33 * s, 0.0, 1.57)
        upper_arm_end = (0.52 * s, 0.0, 1.34)
        elbow = (0.56 * s, 0.0, 1.28)
        forearm_end = (0.55 * s, 0.0, 1.00)
        wrist = (0.55 * s, 0.0, 0.95)
        hand_end = (0.55 * s, -0.005, 0.78)

        # Shoulder
        parts.append(
            add_joint(
                f"Shoulder_{side}",
                shoulder,
                0.145
            )
        )

        # Upper arm
        parts.extend(
            add_capsule_segment(
                f"UpperArm_{side}",
                shoulder,
                elbow,
                0.115,
                0.095
            )
        )

        # Elbow
        parts.append(
            add_joint(
                f"Elbow_{side}",
                elbow,
                0.095
            )
        )

        # Forearm
        parts.extend(
            add_capsule_segment(
                f"Forearm_{side}",
                elbow,
                wrist,
                0.090,
                0.070
            )
        )

        # Wrist
        parts.append(
            add_joint(
                f"Wrist_{side}",
                wrist,
                0.070
            )
        )

        # Simplified hand
        parts.append(
            add_uv_sphere(
                f"Hand_{side}",
                hand_end,
                (0.085, 0.055, 0.145)
            )
        )

    # ========================================================
    # LEGS
    # ========================================================

    for side in (-1, 1):

        s = float(side)

        hip = (0.16 * s, 0.0, 0.88)
        upper_leg_end = (0.17 * s, 0.0, 0.52)

        knee = (0.17 * s, 0.0, 0.49)
        lower_leg_end = (0.17 * s, 0.0, 0.16)

        ankle = (0.17 * s, 0.0, 0.12)

        # Hip volume
        parts.append(
            add_joint(
                f"Hip_{side}",
                hip,
                0.16
            )
        )

        # Upper leg
        parts.extend(
            add_capsule_segment(
                f"Thigh_{side}",
                hip,
                upper_leg_end,
                0.145,
                0.115
            )
        )

        # Knee
        parts.append(
            add_joint(
                f"Knee_{side}",
                knee,
                0.105
            )
        )

        # Lower leg
        parts.extend(
            add_capsule_segment(
                f"LowerLeg_{side}",
                knee,
                lower_leg_end,
                0.095,
                0.070
            )
        )

        # Ankle
        parts.append(
            add_joint(
                f"Ankle_{side}",
                ankle,
                0.070
            )
        )

        # Foot
        parts.append(
            add_uv_sphere(
                f"Foot_{side}",
                (0.17 * s, -0.075, 0.075),
                (0.105, 0.18, 0.075)
            )
        )

    return [obj for obj in parts if obj is not None]


# ------------------------------------------------------------
# JOIN ALL VOLUMES
# ------------------------------------------------------------

def join_objects(objects):
    """
    Join all generated pieces into one mesh object.
    """
    bpy.ops.object.select_all(action='DESELECT')

    for obj in objects:
        if obj and obj.name in bpy.data.objects:
            obj.select_set(True)

    bpy.context.view_layer.objects.active = objects[0]

    bpy.ops.object.join()

    result = bpy.context.object
    result.name = BODY_NAME

    return result


# ------------------------------------------------------------
# VOXEL REMESH
# ------------------------------------------------------------

def voxel_remesh(obj):
    """
    Convert the overlapping primitives into a single continuous
    manifold-style surface.

    Blender's voxel remesh works on the combined mesh volume.
    """

    bpy.context.view_layer.objects.active = obj
    obj.select_set(True)

    # Apply any remaining transforms
    bpy.ops.object.transform_apply(
        location=False,
        rotation=False,
        scale=True
    )

    # Add Remesh modifier
    remesh = obj.modifiers.new(
        name="Unified_Voxel_Remesh",
        type='REMESH'
    )

    remesh.mode = 'VOXEL'
    remesh.voxel_size = VOXEL_SIZE
    remesh.use_smooth_shade = True

    bpy.ops.object.modifier_apply(
        modifier=remesh.name
    )

    return obj


# ------------------------------------------------------------
# SMOOTH + SUBDIVISION
# ------------------------------------------------------------

def smooth_mesh(obj):
    """Smooth the resulting surface."""
    mesh = obj.data

    # Smooth vertices
    for vertex in mesh.vertices:
        vertex.select = True

    bpy.context.view_layer.objects.active = obj

    # Use Blender's operator for controlled smoothing
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')

    try:
        bpy.ops.mesh.vertices_smooth(
            factor=SMOOTH_FACTOR,
            repeat=2
        )
    except RuntimeError:
        pass

    bpy.ops.object.mode_set(mode='OBJECT')

    # Smooth shading
    for polygon in mesh.polygons:
        polygon.use_smooth = True


def add_subdivision(obj):
    """Add a light subdivision pass."""
    if SUBDIVISION_LEVELS <= 0:
        return

    modifier = obj.modifiers.new(
        name="Surface_Subdivision",
        type='SUBSURF'
    )

    modifier.subdivision_type = 'CATMULL_CLARK'
    modifier.levels = SUBDIVISION_LEVELS
    modifier.render_levels = SUBDIVISION_LEVELS

    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.modifier_apply(
        modifier=modifier.name
    )


# ------------------------------------------------------------
# NORMALS / CLEANUP
# ------------------------------------------------------------

def cleanup_mesh(obj):
    """Perform basic topology cleanup."""
    bpy.context.view_layer.objects.active = obj

    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')

    # Merge extremely close vertices
    bpy.ops.mesh.remove_doubles(threshold=0.0005)

    # Recalculate normals
    bpy.ops.mesh.normals_make_consistent(
        inside=False
    )

    bpy.ops.object.mode_set(mode='OBJECT')

    # Ensure smooth shading
    for polygon in obj.data.polygons:
        polygon.use_smooth = True


# ------------------------------------------------------------
# SIMPLE MATERIAL
# ------------------------------------------------------------

def create_material(obj):
    """Create a neutral clay-like material."""
    material = bpy.data.materials.new(
        name="Humanoid_Clay"
    )

    material.diffuse_color = (
        0.42,
        0.28,
        0.20,
        1.0
    )

    material.roughness = 0.72

    obj.data.materials.append(material)


# ------------------------------------------------------------
# MIRROR SETUP
# ------------------------------------------------------------

def setup_mirror_reference(obj):
    """
    Add a disabled Mirror modifier as a reference for future
    symmetric editing.

    The actual body is already symmetrical because it was
    procedurally generated from paired coordinates.
    """

    mirror = obj.modifiers.new(
        name="Symmetry_Reference",
        type='MIRROR'
    )

    mirror.use_axis[0] = True
    mirror.use_clip = True
    mirror.use_mirror_merge = True
    mirror.merge_threshold = 0.001

    # Disable viewport/render so the already-complete mesh
    # isn't duplicated.
    mirror.show_viewport = False
    mirror.show_render = False


# ------------------------------------------------------------
# GROUND / CAMERA-FRIENDLY POSITION
# ------------------------------------------------------------

def center_on_ground(obj):
    """Move mesh so the lowest point rests approximately on Z=0."""
    world_z = [
        obj.matrix_world @ v.co
        for v in obj.data.vertices
    ]

    if not world_z:
        return

    lowest = min(v.z for v in world_z)

    obj.location.z -= lowest


# ------------------------------------------------------------
# MAIN
# ------------------------------------------------------------

def main():

    print("========================================")
    print("Creating procedural humanoid...")
    print("========================================")

    # Start clean
    clear_scene()

    # Build overlapping anatomical volumes
    parts = build_humanoid()

    print(f"Generated {len(parts)} primitive volumes.")

    # Join them into a temporary mesh
    humanoid = join_objects(parts)

    print("Joined primitive volumes.")

    # Convert overlapping volumes into one continuous surface
    humanoid = voxel_remesh(humanoid)

    print("Voxel remesh complete.")

    # Smooth the surface
    smooth_mesh(humanoid)

    # Light subdivision
    add_subdivision(humanoid)

    # Final cleanup
    cleanup_mesh(humanoid)

    # Place feet on ground
    center_on_ground(humanoid)

    # Material
    create_material(humanoid)

    # Optional mirror reference
    setup_mirror_reference(humanoid)

    # Select final object
    bpy.ops.object.select_all(action='DESELECT')
    humanoid.select_set(True)

    if SELECT_RESULT:
        bpy.context.view_layer.objects.active = humanoid

    print("========================================")
    print("Humanoid generation complete.")
    print(f"Object: {humanoid.name}")
    print(f"Vertices: {len(humanoid.data.vertices)}")
    print(f"Polygons: {len(humanoid.data.polygons)}")
    print("========================================")


# ------------------------------------------------------------
# RUN
# ------------------------------------------------------------

if __name__ == "__main__":
    main()

 

Jag bifogar en bild på modellen också:

Dölj innehåll

screenshot_blender_5.2LTS_humanoid.thumb.png.61faf96518f8bd6a6aa5fb178e073c4d.png

Även om det inte ser ut som en "riktig" människa, så går det säkert att prompta ChatGPT eller andra AI agenter/modeller för att få en mer "verklig" person? Bara coolt att det fungerar att göra så här tycker jag?

Den här idén om att prompta AI för Blender fick jag i somras och tänkte direkt att "fan, det borde gå då allt är Open Source m.m." och det verkar ju fungera i praktiken med (även om resultatet är beroende på prompt såklart)?

Kul med kodningsrenässans på forumet, hehe.:D

Länk till kommentar
Dela på andra sidor

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Gäst
Skriv inlägg...

×   Innehåll kopierat inklusive formatering.   Ta bort formatering

  Only 75 emoji are allowed.

×   Din länk har expanderats till ett media-block.   Visa länk istället

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...