I have found out why I thought
CreateImageFromMemblock() was too slow. Turns out what actually slowed down my code was adjusting each memblock pixel in real-time!
So I have tried to get into Bengismos code, and I feel that I have gotten some degree of understanding. I converted it to VR, using the B Button on the Right controller for drawing. Of course, the canvas size of 10 x 10 meters was way too big. Not something you'll ever notice on the monitor, but in VR, it's rather extreme!
The painting seems to be offset half a pixelart-pixel vertically and horizontally. Should be easy to adjust, or so I think. I'm still in the process of trying to 'get', the code, but I'm getting there, slowly.
// Project: 3D Painting
// Created: 2018-03-26
// show all errors
SetErrorMode(2)
// set window properties
SetWindowTitle( "Real time 3D image memblock editing" )
SetWindowSize( 800, 600, 0 )
SetWindowAllowResize( 0 ) // dont allow the user to resize the window
// set display properties
SetVirtualResolution( 800, 600 )
SetCameraPosition(1,0,5,-10)
SetAntialiasMode( 1 ) // 0=off, 1=4xMSAA
SetDefaultMagFilter( 1 ) // 0=nearest, 1=linear
SetDefaultMinFilter( 1 ) // 0=nearest, 1=linear
SetSyncRate( 90, 0 )
UseNewDefaultFonts( 1 )
SetPrintSize(20)
//Set the error reporting for debugging.
SetErrorMode( 2 )
//Load the AGKVR plugin
#import_plugin AGKVR
/*******************************************************************************
VR TECH STUFFIE
*******************************************************************************/
//Set the Camera Range in AGKVR
//It is necessary to use this command for setting the camera's range instead of the standard AGK SetCameraRange command
//AGKVR.SetCameraRange( 0.01, 1000.0 )
AGKVR.SetCameraRange( 0.001, 1000.0 )
//Initialiaze AGKVR
// The parameters are the Right and Left Eye image ID's that will be used to render to the HMD
InitError As Integer
RightEyeImg As Integer = 500
LeftEyeImg As Integer = 501
InitError = AGKVR.Init( RightEyeImg, LeftEyeImg )
// InitError = 0: SUCCESS!
// InitError = 1: Unable to init VR runtime
// InitError = 2: Compositor initialization failed.
//This command will lock the player's heading direction
//to follow the turn angle of the HMD. This would be common in FPS games, where
//you want the forward moving direction's turn angle to change based on where the
//player is looking. LockPlayerTurn is ON(1) by default
AGKVR.LockPlayerTurn( 1 )
//This command will lock the player's heading direction (forward on the Z axis)
//to follow the pitch angle of the HMD. This would be useful in a freeflight style game
//where you want the forward moving direction's pitch angle to change based on where the
//player is looking. LockPlayerPitch is OFF(0) by default
AGKVR.LockPlayerPitch( 0 )
/*******************************************************************************
WORLD DETAILS
*******************************************************************************/
// Ground plane
GroundObj = CreateObjectPlane(100,100)
RotateObjectGlobalX(GroundObj,90)
SetObjectPosition(GroundObj, 0,-10,0)
SetObjectColor(GroundObj,5,120,5,255)
// skybox
SetSkyBoxVisible(1)
SetSkyBoxHorizonColor(10,10,100)
SetSkyBoxSkyColor(20,20,200)
/*******************************************************************************
PAINTING
*******************************************************************************/
// pixel width and height of image
global xw = 320
global yw = 240
// create a virtual backbuffer to draw on
Im = CreateImageMemblock(1, xw, yw)
// create a sprite that uses the image memblock created above
//CreateSprite(1,1)
// create the canvas plane
canvasWidth# = 6.4
canvasHeight# = 4.8
canvasPlane = CreateObjectPlane ( canvasWidth#, canvasHeight# )
SetObjectImage ( canvasPlane, 1, 0 )
SetObjectTransparency ( canvasPlane, 0 )
// Make some legs for our painting sign
PostL = CreateObjectBox ( 0.8, 15, 0.8 )
SetObjectColor ( PostL, 120, 120, 10, 255 )
SetObjectPosition ( PostL, -4, -5, 0.5 )
PostR = CloneObject ( PostL)
SetObjectPosition ( PostR, 4, -5, 0.5 )
/***************************************
CREATE LASER POINTER
***************************************/
Global laserPointer
laserPointer = CreateObjectBox (0.001, 0.002, 50.0)
SetObjectLightMode(laserPointer, 0)
SetObjectColor(laserPointer, 255, 0, 0, 255)
SetObjectCullMode( laserPointer, 0 ) // 0 draws backfaces too
SetObjectTransparency( laserPointer, 1 )
// 0 = opaque (transparency disabled)
// 1 = alpha blended (transparency enabled)
// 2 = additive blended
SetObjectCollisionMode(laserPointer,0) // So it won't be colorized or have its color picked
// used to aim
Global SightB
SightB = CreateObjectBox (0.03, 0.03, 0.03)
SetObjectColor (SightB, 255, 0, 0, 255)
SetObjectVisible(SightB, 0)
do
/***************************************
LASER POINTER
***************************************/
SetObjectPosition( laserPointer, AGKVR.GetRightHandX(), AGKVR.GetRightHandY(), AGKVR.GetRightHandZ())
SetObjectRotation( laserPointer, AGKVR.GetRightHandAngleX(), AGKVR.GetRightHandAngleY(), AGKVR.GetRightHandAngleZ() )
RotateObjectLocalX ( laserPointer, 45.0) // rotate to get pointing direction
MoveObjectLocalZ( laserPointer, 25.0) // move it half the laserpointers length
MoveObjectLocalZ( laserPointer, 0.05) // move it a bit forward
/***************************************
Right Hand: Paint with B button
***************************************/
if AGKVR.RightController_Button1()
SetObjectPosition( SightB, AGKVR.GetRightHandX(), AGKVR.GetRightHandY(), AGKVR.GetRightHandZ())
SetObjectRotation( SightB, AGKVR.GetRightHandAngleX(), AGKVR.GetRightHandAngleY(), AGKVR.GetRightHandAngleZ())
rotateObjectLocalX (SightB, 45.0)
MoveObjectLocalZ(SightB, 50.0)
ObjHit = ObjectRayCast( 0, AGKVR.GetRightHandX(), AGKVR.GetRightHandY(), AGKVR.GetRightHandZ(), GetObjectX(SightB), GetObjectY(SightB), GetObjectZ(SightB) )
// If the raycast hits the canvas
if objhit = canvasPlane
xp# = (GetObjectRayCastX(0)+(canvasWidth#*0.5)) / canvasWidth#*xw // Returns the X position of the spot we are pointing at
yp# = (-GetObjectRayCastY(0)+(canvasHeight#*0.5)) / canvasHeight#*yw
Dot(xp#,yp#) // Draw the pixel
endif
endif
/***************************************
Paint with mouse
***************************************/
if GetPointerState() = 1 // if mouse is detected
x = GetPointerX()
y = GetPointerY()
oldPosX# = GetCameraX(1) // # means float ... (yeah, I'm at that level)
oldPosY# = GetCameraY(1)
oldPosZ# = GetCameraZ(1)
newPosX# = oldPosX# + (Get3DVectorXFromScreen( x, y )*100) // alright, I don't get exactly how this stuff works, but
newPosY# = oldPosY# + (Get3DVectorYFromScreen( x, y )*100) // I get which values it returns
newPosZ# = oldPosZ# + (Get3DVectorZFromScreen( x, y )*100)
ObjHit = ObjectRayCast ( 0, oldPosX#, oldPosY#, oldPosZ#, newPosX#, newPosY#, newPosZ# )
// If the raycast hits the canvas
if objhit = canvasPlane
xp# = (GetObjectRayCastX(0)+(canvasWidth#*0.5)) / canvasWidth#*xw // Returns the X position of the spot we are pointing at
yp# = (-GetObjectRayCastY(0)+(canvasHeight#*0.5)) / canvasHeight#*yw
Dot(xp#,yp#) // Draw the pixel
/*
Dot(xp#-1,yp#) // Draw more pixels around it
Dot(xp#+1,yp#)
Dot(xp#,yp#+1)
Dot(xp#,yp#-1)
*/
//Print ("Hit: X " + str(xp#) + " y " + str(yp#) )
endif
endif
if getrawKeyPressed( 67) then ClearImageMemblock()
// Create a new colour
SetDotColour(Random(20,255),Random(20,255),Random(20,255))
SetDotColour(255,0,0)
// update the image from the memblock
CreateImageFromMemblock(1,Im)
SetImageMinFilter(1, 0) // because, "pixelart"
SetImageMagFilter(1, 0)
// If mouse is pressed - Clear the "backbuffer" (the memblock)
//if GetPointerPressed() then ClearImageMemblock()
/***************************************
Update the player
***************************************/
AGKVR.UpdatePlayer( )
/***************************************
RENDER TO VR
***************************************/
//This command renders to the HMD.
AGKVR.Render( )
FPSCamera()
Print( "FPS: " + str(ScreenFPS()) )
Print( "Press left mouse to draw" )
Print( "Use WSAD to fly around" )
Print( "Use right mouse to rotate camera" )
Print( "Press C to clear your canvas" )
Sync()
loop
// ALL THE REAL WORK IS DONE BELOW
// Variables to store the memblock and current colour
global Im
global Rv
global Bv
global Gv
/*******************************************************************************
FUNCTIONS
*******************************************************************************/
// This sets the current plot colour
function SetDotColour(Red as integer, Green as integer, Blue as integer)
Rv = Red
Bv = Blue
Gv = Green
endfunction
// this plots a single pixel
function Dot(x as integer,y as integer)
if x<0 then exitfunction
if y<0 then exitfunction
if x>xw then exitfunction
if y>yw-1 then exitfunction
offset = 12 + (4*(x + (y*GetMemblockInt(Im,0))))
SetMemblockbyte(Im,offset,Rv) // red
SetMemblockbyte(Im,offset+1,Bv) // green
SetMemblockbyte(Im,offset+2,Gv) // blue
SetMemblockbyte(Im,offset+3,255) // alpha (Not really needed, since we won't change this)
endfunction
// this clears the virtual backbuffer
function ClearImageMemblock()
offset = 12
for ix = 0 to GetMemblockInt(Im,0)-1
for iy = 0 to GetMemblockInt(Im,4)-1
SetMemblockInt(Im,offset,0) // clears
offset = offset + 4
next iy
next ix
// Theres a quicker way of doing this but I left it like this to show how it works
endfunction
// Creating a memory block from scratch, instead of just importing a .jpg? Okay, now you're just showing off!!! :-p
function CreateImageMemblock(ID as integer, width as integer, height as integer)
Im = CreateMemblock(12 + (4 * width * height))
// Set the width and heights etc..
SetMemblockInt(Im,0,width)
SetMemblockInt(Im,4,height)
SetMemblockInt(Im,8,32)
pixels = width*height
bytes = pixels*4
for i=12 to bytes+11
SetMemblockByte(Im,i,255)
next i
// Create an image from the memblock
CreateImageFromMemblock(ID,Im)
endfunction Im
// this plots a single pixel
function GetPixel(x as integer,y as integer)
offset = 12 + (4*(x + (y*GetMemblockInt(Im,0))))
col = GetMemblockInt(Im,offset)
endfunction col
// camera starts in free mode
global cameraMode = 0
global startx#
global starty#
global angx#
global angy#
global pressed
Function FPSCamera()
// move the camera
speed# = GetFrameTime()*15
if ( GetRawKeyState( 16 ) ) then speed# = speed#*0.2
//if ( cameraMode = 1 ) then speed# = 0.05
if ( GetRawKeyState( 87 ) ) then MoveCameraLocalZ( 1, speed# )
if ( GetRawKeyState( 83 ) ) then MoveCameraLocalZ( 1, -speed# )
if ( GetRawKeyState( 65 ) ) then MoveCameraLocalX( 1, -speed# )
if ( GetRawKeyState( 68 ) ) then MoveCameraLocalX( 1, speed# )
if ( GetRawKeyState( 81 ) ) then MoveCameraLocalY( 1, -speed# )
if ( GetRawKeyState( 69 ) ) then MoveCameraLocalY( 1, speed# )
// rotate the camera
//if ( GetPointerPressed() )
if ( GetRawMouseRightPressed() )
startx# = GetPointerX()
starty# = GetPointerY()
angx# = GetCameraAngleX(1)
angy# = GetCameraAngleY(1)
pressed = 1
endif
// if ( GetPointerState() = 1 )
if ( GetRawMouseRightState() = 1)
fDiffX# = (GetPointerX() - startx#)/4.0
fDiffY# = (GetPointerY() - starty#)/4.0
newX# = angx# + fDiffY#
if ( newX# > 89 ) then newX# = 89
if ( newX# < -89 ) then newX# = -89
SetCameraRotation( 1, newX#, angy# + fDiffX#, 0 )
endif
Endfunction