mirror of
https://github.com/QB64Official/qb64.git
synced 2024-09-01 23:20:16 +00:00
712 lines
23 KiB
QBasic
712 lines
23 KiB
QBasic
|
CHDIR "programs\samples\open_gl"
|
||
|
|
||
|
' This example shows how models with textures or materials can be displayed with OpenGL using QB64
|
||
|
'
|
||
|
'IMPORTANT:
|
||
|
' Whilst the .X file loader is optimized for speed, it is very incomplete:
|
||
|
' -only .X files in text file format
|
||
|
' -only one object, not a cluster of objects
|
||
|
' -if using a texture, use a single texture which will be applied to all materials
|
||
|
' -all the 3D models in this example were exported from Blender, a free 3D creation tool
|
||
|
' Blender tips: CTRL+J to amalgamate objects, select object to export first, in the UV/image-editor
|
||
|
' window you can export the textures built into your .blend file, apply the decimate
|
||
|
' modifier to reduce your polygon count to below 10000, preferably ~3000 or less
|
||
|
' This program is not a definitive guide to OpenGL in any way
|
||
|
' The GLH functions are something I threw together to stop people crashing their code by making
|
||
|
' calls to OpenGL with incorrectly sized memory regions. The GLH... prefixed commands are not mandatory or
|
||
|
' part of QB64, nor do they represent a complete library of helper commands.
|
||
|
' Lighting is not this example's strongest point, there's probably some work to do on light positioning
|
||
|
' and vertex normals
|
||
|
'
|
||
|
'Finally, I hope you enjoy this program as much as I enjoyed piecing it together,
|
||
|
' Galleon
|
||
|
|
||
|
'###################################### GLH SETUP #############################################
|
||
|
|
||
|
'Used to manage textures
|
||
|
TYPE DONT_USE_GLH_Handle_TYPE
|
||
|
in_use AS _BYTE
|
||
|
handle AS LONG
|
||
|
END TYPE
|
||
|
|
||
|
'Used by GLH RGB/etc helper functions
|
||
|
DIM SHARED DONT_USE_GLH_COL_RGBA(1 TO 4) AS SINGLE
|
||
|
|
||
|
REDIM SHARED DONT_USE_GLH_Handle(1000) AS DONT_USE_GLH_Handle_TYPE
|
||
|
|
||
|
'.X Format Model Loading Data
|
||
|
TYPE VERTEX_TYPE
|
||
|
X AS DOUBLE
|
||
|
Y AS DOUBLE
|
||
|
Z AS DOUBLE
|
||
|
NX AS DOUBLE
|
||
|
NY AS DOUBLE
|
||
|
NZ AS DOUBLE
|
||
|
END TYPE
|
||
|
REDIM SHARED VERTEX(1) AS VERTEX_TYPE
|
||
|
DIM SHARED VERTICES AS LONG
|
||
|
TYPE FACE_CORNER_TYPE
|
||
|
V AS LONG 'the vertex index
|
||
|
TX AS SINGLE 'texture X coordinate
|
||
|
TY AS SINGLE 'texture Y coordinate
|
||
|
END TYPE
|
||
|
TYPE FACE_TYPE
|
||
|
V1 AS FACE_CORNER_TYPE
|
||
|
V2 AS FACE_CORNER_TYPE
|
||
|
V3 AS FACE_CORNER_TYPE
|
||
|
Material AS LONG
|
||
|
Index AS LONG
|
||
|
END TYPE
|
||
|
REDIM SHARED FACE(1) AS FACE_TYPE
|
||
|
DIM SHARED FACES AS LONG
|
||
|
TYPE MATERIAL_RGBAI_TYPE
|
||
|
R AS SINGLE
|
||
|
G AS SINGLE
|
||
|
B AS SINGLE
|
||
|
A AS SINGLE
|
||
|
Intensity AS SINGLE
|
||
|
END TYPE
|
||
|
TYPE MATERIAL_TYPE
|
||
|
Diffuse AS MATERIAL_RGBAI_TYPE 'regular col
|
||
|
Specular AS MATERIAL_RGBAI_TYPE 'hightlight/shine col
|
||
|
Texture_Image AS LONG 'both an image and a texture handle are held
|
||
|
Texture AS LONG 'if 0, there is no texture
|
||
|
END TYPE
|
||
|
REDIM SHARED MATERIAL(1) AS MATERIAL_TYPE
|
||
|
DIM SHARED MATERIALS AS LONG
|
||
|
|
||
|
'##############################################################################################
|
||
|
|
||
|
DIM SHARED AllowSubGL
|
||
|
|
||
|
SCREEN _NEWIMAGE(1024, 768, 32)
|
||
|
|
||
|
backdrop = _LOADIMAGE("backdrop_tron.png")
|
||
|
|
||
|
DIM SHARED rot1
|
||
|
DIM SHARED rot2, rot3
|
||
|
DIM SHARED scale: scale = 1
|
||
|
|
||
|
'Load (default) model
|
||
|
GLH_Load_Model_Format_X "marty.x", "marty_tmap.png"
|
||
|
'draw backdrop
|
||
|
_PUTIMAGE , backdrop: _DONTBLEND: LINE (200, 200)-(500, 500), _RGBA(0, 255, 255, 0), BF: _BLEND
|
||
|
|
||
|
AllowSubGL = 1
|
||
|
|
||
|
DO
|
||
|
'This is our program's main loop
|
||
|
_LIMIT 100
|
||
|
LOCATE 1, 1
|
||
|
PRINT "Mouse Input:"
|
||
|
PRINT "{Horizonal Movement}Spin"
|
||
|
PRINT "{Vertical Movement}Flip"
|
||
|
PRINT "{Wheel}Scale"
|
||
|
PRINT
|
||
|
PRINT "Keyboard comands:"
|
||
|
PRINT "Switch rendering order: {1}GL behind, {2}GL on top, {3}GL only, good for speed"
|
||
|
PRINT "Switch/Load model: {A}Zebra, {B}Pig, {C}Car"
|
||
|
|
||
|
k$ = INKEY$
|
||
|
IF k$ = "1" THEN _GLRENDER _BEHIND
|
||
|
IF k$ = "2" THEN _GLRENDER _ONTOP
|
||
|
IF k$ = "3" THEN _GLRENDER _ONLY
|
||
|
|
||
|
|
||
|
PRINT "Angles:"; rot1, rot2, rot3
|
||
|
|
||
|
|
||
|
IF UCASE$(k$) = "A" THEN
|
||
|
AllowSubGL = 0
|
||
|
GLH_Load_Model_Format_X "marty.x", "marty_tmap.png"
|
||
|
_PUTIMAGE , backdrop: _DONTBLEND: LINE (200, 200)-(500, 500), _RGBA(0, 255, 255, 0), BF: _BLEND
|
||
|
AllowSubGL = 1
|
||
|
END IF
|
||
|
|
||
|
IF UCASE$(k$) = "B" THEN
|
||
|
AllowSubGL = 0
|
||
|
GLH_Load_Model_Format_X "piggy_mini3.x", ""
|
||
|
_PUTIMAGE , backdrop: _DONTBLEND: LINE (200, 200)-(500, 500), _RGBA(0, 255, 255, 0), BF: _BLEND
|
||
|
AllowSubGL = 1
|
||
|
END IF
|
||
|
|
||
|
IF UCASE$(k$) = "C" THEN
|
||
|
AllowSubGL = 0
|
||
|
GLH_Load_Model_Format_X "gasprin.x", "gasprin_tmap.png"
|
||
|
_PUTIMAGE , backdrop: _DONTBLEND: LINE (200, 200)-(500, 500), _RGBA(0, 255, 255, 0), BF: _BLEND
|
||
|
AllowSubGL = 1
|
||
|
END IF
|
||
|
|
||
|
DO WHILE _MOUSEINPUT
|
||
|
scale = scale * (1 - (_MOUSEWHEEL * .1))
|
||
|
rot1 = _MOUSEX
|
||
|
rot2 = _MOUSEY
|
||
|
LOOP
|
||
|
|
||
|
IF k$ = "." THEN rot3 = rot3 + 1
|
||
|
IF k$ = "," THEN rot3 = rot3 - 1
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
LOOP UNTIL k$ = CHR$(27)
|
||
|
END
|
||
|
|
||
|
'this specially named sub "_GL" is detected by QB64 and adds support for OpenGL commands
|
||
|
'it is called automatically whenever the underlying software deems an update is possible
|
||
|
'usually/ideally, this is in sync with your monitor's refresh rate
|
||
|
SUB _GL STATIC
|
||
|
'STATIC was used above to make all variables in this sub maintain their values between calls to this sub
|
||
|
|
||
|
IF AllowSubGL = 0 THEN EXIT SUB 'we aren't ready yet!
|
||
|
|
||
|
'timing is everything, we don't know how fast the 3D renderer will call this sub to we use timers to smooth things out
|
||
|
T# = TIMER(0.001)
|
||
|
IF ETT# = 0 THEN ETT# = T#
|
||
|
ET# = T# - ETT#
|
||
|
ETT# = T#
|
||
|
|
||
|
IF sub_gl_called = 0 THEN
|
||
|
sub_gl_called = 1 'we only need to perform the following code once
|
||
|
'...
|
||
|
END IF
|
||
|
|
||
|
'These settings affect how OpenGL will render our content
|
||
|
'!!! THESE SETTINGS ARE TO SHOW HOW ALPHA CAN WORK, BUT IT IS 10x FASTER WHEN ALPHA OPTIONS ARE DISABLED !!!
|
||
|
'*** every setting must be reset because SUB _GL cannot guarantee settings have not changed since last time ***
|
||
|
_glMatrixMode _GL_PROJECTION 'Select The Projection Matrix
|
||
|
_glLoadIdentity 'Reset The Projection Matrix
|
||
|
_gluPerspective 45, _WIDTH(0) / _HEIGHT(0), 1, 100 'QB64 internally supports this GLU command for convenience sake, but does not support GLU
|
||
|
_glEnable _GL_TEXTURE_2D
|
||
|
_glEnable _GL_BLEND
|
||
|
_glBlendFunc _GL_SRC_ALPHA, _GL_ONE_MINUS_SRC_ALPHA 'how alpha values are interpretted
|
||
|
_glEnable _GL_DEPTH_TEST 'use the zbuffer
|
||
|
_glDepthMask _GL_TRUE
|
||
|
_glAlphaFunc _GL_GREATER, 0.5 'dont do anything if alpha isn't greater than 0.5 (or 128)
|
||
|
_glEnable _GL_ALPHA_TEST
|
||
|
_glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_MAG_FILTER, _GL_LINEAR
|
||
|
_glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_MIN_FILTER, _GL_LINEAR
|
||
|
'**************************************************************************************************************
|
||
|
|
||
|
_glMatrixMode _GL_MODELVIEW 'Select The Modelview Matrix
|
||
|
_glLoadIdentity 'Reset The Modelview Matrix
|
||
|
|
||
|
|
||
|
|
||
|
'setup our light
|
||
|
_glEnable _GL_LIGHTING
|
||
|
_glEnable _GL_LIGHT0
|
||
|
_glLightfv _GL_LIGHT0, _GL_DIFFUSE, GLH_RGB(.8, .8, .8)
|
||
|
_glLightfv _GL_LIGHT0, _GL_AMBIENT, GLH_RGB(0.1, 0.1, 0.1)
|
||
|
_glLightfv _GL_LIGHT0, _GL_SPECULAR, GLH_RGB(0.3, 0.3, 0.3)
|
||
|
|
||
|
light_rot = light_rot + ET#
|
||
|
_glLightfv _GL_LIGHT0, _GL_POSITION, GLH_RGBA(SIN(light_rot) * 20, COS(light_rot) * 20, 20, 1)
|
||
|
|
||
|
|
||
|
_glTranslatef 0, 0, -20 'Translate Into The Screen
|
||
|
_glRotatef rot1, 0, 1, 0
|
||
|
_glRotatef rot2, 1, 0, 0
|
||
|
_glRotatef rot3, 0, 0, 1
|
||
|
|
||
|
|
||
|
|
||
|
current_m = -1
|
||
|
FOR F = 1 TO FACES
|
||
|
|
||
|
m = FACE(F).Material
|
||
|
IF m <> current_m THEN 'we don't switch materials unless we have to
|
||
|
IF current_m <> -1 THEN _glEnd 'stop rendering triangles so we can change some settings
|
||
|
current_m = m
|
||
|
IF MATERIAL(m).Texture_Image THEN
|
||
|
|
||
|
_glEnable _GL_TEXTURE_2D
|
||
|
_glDisable _GL_COLOR_MATERIAL
|
||
|
_glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_MAG_FILTER, _GL_LINEAR 'seems these need to be respecified
|
||
|
_glTexParameteri _GL_TEXTURE_2D, _GL_TEXTURE_MIN_FILTER, _GL_LINEAR
|
||
|
|
||
|
|
||
|
IF MATERIAL(m).Texture = 0 THEN
|
||
|
MATERIAL(m).Texture = GLH_Image_to_Texture(MATERIAL(m).Texture_Image)
|
||
|
END IF
|
||
|
GLH_Select_Texture MATERIAL(m).Texture
|
||
|
|
||
|
_glMaterialfv _GL_FRONT, _GL_DIFFUSE, GLH_RGBA(1, 1, 1, 1)
|
||
|
|
||
|
ELSE
|
||
|
'use materials, disable textures
|
||
|
_glDisable _GL_TEXTURE_2D
|
||
|
_glDisable _GL_COLOR_MATERIAL
|
||
|
|
||
|
mult = MATERIAL(m).Diffuse.Intensity 'otherwise known as "power"
|
||
|
r = MATERIAL(m).Diffuse.R * mult
|
||
|
g = MATERIAL(m).Diffuse.G * mult
|
||
|
b = MATERIAL(m).Diffuse.B * mult
|
||
|
' _glColor3f r, g, b
|
||
|
_glMaterialfv _GL_FRONT, _GL_DIFFUSE, GLH_RGBA(r, g, b, 1)
|
||
|
|
||
|
mult = MATERIAL(m).Specular.Intensity
|
||
|
r = MATERIAL(m).Specular.R * mult
|
||
|
g = MATERIAL(m).Specular.G * mult
|
||
|
b = MATERIAL(m).Specular.B * mult
|
||
|
_glMaterialfv _GL_FRONT, _GL_SPECULAR, GLH_RGBA(r, g, b, 1)
|
||
|
|
||
|
END IF
|
||
|
|
||
|
_glBegin _GL_TRIANGLES
|
||
|
|
||
|
END IF
|
||
|
|
||
|
FOR s = 1 TO 3
|
||
|
|
||
|
IF s = 1 THEN v = FACE(F).V1.V
|
||
|
IF s = 2 THEN v = FACE(F).V2.V
|
||
|
IF s = 3 THEN v = FACE(F).V3.V
|
||
|
v = v + 1
|
||
|
|
||
|
'vertex
|
||
|
x = (VERTEX(v).X + 0) * scale
|
||
|
y = (VERTEX(v).Y + 0) * scale
|
||
|
z = (VERTEX(v).Z + 0) * scale
|
||
|
'normal direction from vertex
|
||
|
nx = VERTEX(v).NX: ny = VERTEX(v).NY: nz = VERTEX(v).NZ
|
||
|
|
||
|
|
||
|
'corner's texture coordinates
|
||
|
IF MATERIAL(m).Texture THEN
|
||
|
IF s = 1 THEN tx = FACE(F).V1.TX: ty = FACE(F).V1.TY
|
||
|
IF s = 2 THEN tx = FACE(F).V2.TX: ty = FACE(F).V2.TY
|
||
|
IF s = 3 THEN tx = FACE(F).V3.TX: ty = FACE(F).V3.TY
|
||
|
_glTexCoord2f tx, ty
|
||
|
END IF
|
||
|
|
||
|
_glNormal3d nx, my, nz
|
||
|
_glVertex3f x, y, z
|
||
|
|
||
|
NEXT
|
||
|
|
||
|
NEXT
|
||
|
_glEnd
|
||
|
|
||
|
END SUB
|
||
|
|
||
|
|
||
|
|
||
|
'QB64 OPEN-GL HELPER MACROS (aka. GLH macros) #######################################################################
|
||
|
|
||
|
SUB GLH_Select_Texture (texture_handle AS LONG) 'turn an image handle into a texture handle
|
||
|
IF texture_handle < 1 OR texture_handle > UBOUND(DONT_USE_GLH_HANDLE) THEN ERROR 258: EXIT FUNCTION
|
||
|
IF DONT_USE_GLH_Handle(texture_handle).in_use = 0 THEN ERROR 258: EXIT FUNCTION
|
||
|
_glBindTexture _GL_TEXTURE_2D, DONT_USE_GLH_Handle(texture_handle).handle
|
||
|
END SUB
|
||
|
|
||
|
FUNCTION GLH_Image_to_Texture (image_handle AS LONG) 'turn an image handle into a texture handle
|
||
|
IF image_handle >= 0 THEN ERROR 258: EXIT FUNCTION 'don't allow screen pages
|
||
|
DIM m AS _MEM
|
||
|
m = _MEMIMAGE(image_handle)
|
||
|
DIM h AS LONG
|
||
|
h = DONT_USE_GLH_New_Texture_Handle
|
||
|
GLH_Image_to_Texture = h
|
||
|
_glBindTexture _GL_TEXTURE_2D, DONT_USE_GLH_Handle(h).handle
|
||
|
_glTexImage2D _GL_TEXTURE_2D, 0, _GL_RGBA, _WIDTH(image_handle), _HEIGHT(image_handle), 0, &H80E1&&, _GL_UNSIGNED_BYTE, m.OFFSET
|
||
|
_MEMFREE m
|
||
|
END FUNCTION
|
||
|
|
||
|
FUNCTION DONT_USE_GLH_New_Texture_Handle
|
||
|
handle&& = 0
|
||
|
_glGenTextures 1, _OFFSET(handle&&)
|
||
|
DONT_USE_GLH_New_Texture_Handle = handle&&
|
||
|
FOR h = 1 TO UBOUND(DONT_USE_GLH_Handle)
|
||
|
IF DONT_USE_GLH_Handle(h).in_use = 0 THEN
|
||
|
DONT_USE_GLH_Handle(h).in_use = 1
|
||
|
DONT_USE_GLH_Handle(h).handle = handle&&
|
||
|
DONT_USE_GLH_New_Texture_Handle = h
|
||
|
EXIT FUNCTION
|
||
|
END IF
|
||
|
NEXT
|
||
|
REDIM _PRESERVE DONT_USE_GLH_Handle(UBOUND(DONT_USE_GLH_HANDLE) * 2) AS DONT_USE_GLH_Handle_TYPE
|
||
|
DONT_USE_GLH_Handle(h).in_use = 1
|
||
|
DONT_USE_GLH_Handle(h).handle = handle&&
|
||
|
DONT_USE_GLH_New_Texture_Handle = h
|
||
|
END FUNCTION
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
SUB GLH_Load_Model_Format_X (Filename$, Optional_Texture_Filename$)
|
||
|
|
||
|
_AUTODISPLAY 'so loading messages can be seen
|
||
|
|
||
|
DEFLNG A-Z
|
||
|
|
||
|
IF LEN(Optional_Texture_Filename$) THEN
|
||
|
texture_image = _LOADIMAGE(Optional_Texture_Filename$, 32)
|
||
|
IF texure_image = -1 THEN texure_image = 0
|
||
|
END IF
|
||
|
|
||
|
'temporary arrays
|
||
|
DIM SIDE_LIST(10000) AS LONG 'used for wrangling triangle-fans/triangle-strips
|
||
|
REDIM TEXCO_TX(1) AS SINGLE
|
||
|
REDIM TEXCO_TY(1) AS SINGLE
|
||
|
REDIM POLY_FACE_INDEX_FIRST(1) AS LONG
|
||
|
REDIM POLY_FACE_INDEX_LAST(1) AS LONG
|
||
|
|
||
|
'buffer file
|
||
|
fh = FREEFILE: OPEN Filename$ FOR BINARY AS #fh: file_data$ = SPACE$(LOF(fh)): GET #fh, , file_data$: CLOSE #fh
|
||
|
|
||
|
file_x = 1
|
||
|
file_data$ = UCASE$(file_data$)
|
||
|
|
||
|
ASC_COMMA = 44
|
||
|
ASC_SEMICOLON = 59
|
||
|
ASC_LBRAC = 123
|
||
|
ASC_RBRAC = 125
|
||
|
ASC_SPACE = 32
|
||
|
ASC_TAB = 9
|
||
|
ASC_CR = 13
|
||
|
ASC_LF = 10
|
||
|
ASC_FSLASH = 47
|
||
|
ASC_DOT = 46
|
||
|
ASC_MINUS = 45
|
||
|
|
||
|
DIM WhiteSpace(255) AS LONG
|
||
|
WhiteSpace(ASC_LF) = -1
|
||
|
WhiteSpace(ASC_CR) = -1
|
||
|
WhiteSpace(ASC_SPACE) = -1
|
||
|
WhiteSpace(ASC_TAB) = -1
|
||
|
|
||
|
DIM FormattingCharacter(255) AS LONG
|
||
|
FormattingCharacter(ASC_COMMA) = -1
|
||
|
FormattingCharacter(ASC_SEMICOLON) = -1
|
||
|
FormattingCharacter(ASC_LBRAC) = -1
|
||
|
FormattingCharacter(ASC_RBRAC) = -1
|
||
|
|
||
|
DIM Numeric(255) AS LONG
|
||
|
FOR a = 48 TO 57
|
||
|
Numeric(a) = -1
|
||
|
NEXT
|
||
|
Numeric(ASC_DOT) = -1
|
||
|
Numeric(ASC_MINUS) = -1
|
||
|
|
||
|
PRINT "Loading model:"
|
||
|
|
||
|
DO
|
||
|
|
||
|
skip_comment:
|
||
|
|
||
|
'find start of element
|
||
|
x1 = -1
|
||
|
FOR x = file_x TO LEN(file_data$)
|
||
|
IF WhiteSpace(ASC(file_data$, x)) = 0 THEN x1 = x: EXIT FOR
|
||
|
NEXT
|
||
|
IF x1 = -1 THEN EXIT DO 'no more data
|
||
|
|
||
|
a = ASC(file_data$, x1)
|
||
|
IF a = ASC_FSLASH THEN 'commend
|
||
|
IF ASC(file_data$, x1 + 1) = ASC_FSLASH THEN
|
||
|
FOR x = x1 TO LEN(file_data$)
|
||
|
a = ASC(file_data$, x)
|
||
|
IF a = ASC_CR OR a = ASC_LF THEN file_x = x + 1: GOTO skip_comment '//.....
|
||
|
NEXT
|
||
|
END IF
|
||
|
END IF
|
||
|
|
||
|
'find end of element
|
||
|
x2 = x1
|
||
|
FOR x = x1 TO LEN(file_data$)
|
||
|
a = ASC(file_data$, x)
|
||
|
IF WhiteSpace(a) THEN
|
||
|
IF a = ASC_CR OR a = ASC_LF THEN EXIT FOR 'it is the end
|
||
|
ELSE
|
||
|
'not whitespace
|
||
|
IF FormattingCharacter(a) THEN EXIT FOR
|
||
|
x2 = x
|
||
|
END IF
|
||
|
NEXT
|
||
|
file_x = x2 + 1
|
||
|
|
||
|
a2$ = MID$(file_data$, x1, x2 - x1 + 1)
|
||
|
|
||
|
IF LEN(skip_until$) THEN
|
||
|
IF a2$ <> skip_until$ THEN GOTO skip_comment
|
||
|
skip_until$ = ""
|
||
|
END IF
|
||
|
|
||
|
|
||
|
|
||
|
a = ASC(a2$)
|
||
|
|
||
|
IF Numeric(a) AND a <> ASC_DOT THEN 'faster than VAL, value conversion
|
||
|
v = 0
|
||
|
dp = 0
|
||
|
div = 1
|
||
|
IF a = ASC_MINUS THEN neg = 1: x1 = 2 ELSE neg = 0: x1 = 1
|
||
|
FOR x = x1 TO LEN(a2$)
|
||
|
a2 = ASC(a2$, x)
|
||
|
IF a2 = ASC_DOT THEN
|
||
|
dp = 1
|
||
|
ELSE
|
||
|
v = v * 10 + (a2 - 48)
|
||
|
IF dp THEN div = div * 10
|
||
|
END IF
|
||
|
NEXT
|
||
|
|
||
|
IF dp = 1 THEN
|
||
|
v# = v
|
||
|
div# = div
|
||
|
IF neg THEN value# = (-v#) / div# ELSE value# = v# / div#
|
||
|
ELSE
|
||
|
IF neg THEN value# = -v ELSE value# = v
|
||
|
END IF
|
||
|
|
||
|
END IF
|
||
|
|
||
|
IF face_input THEN
|
||
|
IF face_input = 3 THEN
|
||
|
IF a2$ = ";" THEN
|
||
|
IF last_a2$ = ";" THEN face_input = 0
|
||
|
SLI = SLI + 1
|
||
|
ELSEIF a2$ = "," THEN
|
||
|
face_input = 2
|
||
|
polygon = polygon + 1
|
||
|
ELSE
|
||
|
SIDE_LIST(SLI) = value#
|
||
|
IF SLI >= 3 THEN
|
||
|
FACES = FACES + 1
|
||
|
IF FACES > UBOUND(FACE) THEN REDIM _PRESERVE FACE(UBOUND(FACE) * 2) AS FACE_TYPE
|
||
|
FACE(FACES).V1.V = SIDE_LIST(1)
|
||
|
FACE(FACES).V2.V = SIDE_LIST(SLI - 1)
|
||
|
FACE(FACES).V3.V = SIDE_LIST(SLI)
|
||
|
IF POLY_FACE_INDEX_FIRST(polygon) = 0 THEN POLY_FACE_INDEX_FIRST(polygon) = FACES
|
||
|
POLY_FACE_INDEX_LAST(polygon) = FACES
|
||
|
FACE(FACES).Index = polygon
|
||
|
END IF
|
||
|
|
||
|
file_x = file_x + 1: a2$ = ";": a = ASC_SEMICOLON: SLI = SLI + 1
|
||
|
|
||
|
|
||
|
END IF
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF face_input = 2 THEN
|
||
|
SIDES = value#
|
||
|
SLI = 0
|
||
|
face_input = 3
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF face_input = 1 THEN
|
||
|
POLYGONS = value#
|
||
|
REDIM _PRESERVE FACE(POLYGONS * 4) AS FACE_TYPE 'estimate triangles in polygons
|
||
|
REDIM POLY_FACE_INDEX_FIRST(POLYGONS) AS LONG
|
||
|
REDIM POLY_FACE_INDEX_LAST(POLYGONS) AS LONG
|
||
|
polygon = 1
|
||
|
face_input = 2
|
||
|
FACES = 0
|
||
|
GOTO done
|
||
|
END IF
|
||
|
END IF
|
||
|
|
||
|
IF mesh_input THEN
|
||
|
IF mesh_input = 5 THEN
|
||
|
IF a = ASC_SEMICOLON THEN
|
||
|
mesh_input = 0: face_input = 1
|
||
|
IF normals_input = 1 THEN
|
||
|
face_input = 0 'face input is unrequired on 2nd pass
|
||
|
skip_until$ = "MESHMATERIALLIST"
|
||
|
END IF
|
||
|
END IF
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF mesh_input = 4 THEN
|
||
|
IF a = ASC_SEMICOLON THEN
|
||
|
'ignore
|
||
|
ELSEIF a = ASC_COMMA THEN
|
||
|
vertex = vertex + 1
|
||
|
ELSE
|
||
|
IF normals_input = 1 THEN
|
||
|
IF plane = 1 THEN VERTEX(vertex).NX = value#
|
||
|
IF plane = 2 THEN VERTEX(vertex).NY = value#
|
||
|
IF plane = 3 THEN VERTEX(vertex).NZ = value#
|
||
|
ELSE
|
||
|
IF plane = 1 THEN VERTEX(vertex).X = value#
|
||
|
IF plane = 2 THEN VERTEX(vertex).Y = value#
|
||
|
IF plane = 3 THEN VERTEX(vertex).Z = value#
|
||
|
END IF
|
||
|
|
||
|
plane = plane + 1
|
||
|
IF plane = 4 THEN
|
||
|
plane = 1
|
||
|
IF vertex = VERTICES THEN mesh_input = 5
|
||
|
END IF
|
||
|
|
||
|
file_x = file_x + 1 'skip next character (semicolon)
|
||
|
|
||
|
END IF
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF mesh_input = 3 THEN
|
||
|
IF a2$ = ";" THEN mesh_input = 4
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF mesh_input = 2 THEN
|
||
|
VERTICES = value#
|
||
|
IF normals_input = 0 THEN
|
||
|
REDIM VERTEX(VERTICES) AS VERTEX_TYPE
|
||
|
REDIM TEXCO_TX(VERTICES) AS SINGLE
|
||
|
REDIM TEXCO_TY(VERTICES) AS SINGLE
|
||
|
END IF
|
||
|
mesh_input = 3
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF mesh_input = 1 THEN
|
||
|
IF a2$ = "{" THEN mesh_input = 2: plane = 1: vertex = 1
|
||
|
GOTO done
|
||
|
END IF
|
||
|
GOTO done
|
||
|
END IF
|
||
|
|
||
|
IF matlist_input THEN
|
||
|
IF matlist_input = 6 THEN
|
||
|
IF a2$ = "," THEN
|
||
|
'do nothing
|
||
|
ELSEIF a2$ = ";" THEN
|
||
|
matlist_input = 0
|
||
|
ELSE
|
||
|
polygon = polygon + 1: m = value#
|
||
|
FOR f = POLY_FACE_INDEX_FIRST(polygon) TO POLY_FACE_INDEX_LAST(polygon)
|
||
|
FACE(f).Material = m + 1
|
||
|
NEXT
|
||
|
END IF
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF matlist_input = 5 AND a2$ = ";" THEN matlist_input = 6: polygon = 0: face_search_start = 1: GOTO done
|
||
|
IF matlist_input = 4 THEN matlist_input = 5: GOTO done
|
||
|
IF matlist_input = 3 AND a2$ = ";" THEN matlist_input = 4: GOTO done
|
||
|
IF matlist_input = 2 THEN MATERIALS = value#: REDIM MATERIAL(MATERIALS) AS MATERIAL_TYPE: matlist_input = 3: GOTO done
|
||
|
IF matlist_input = 1 AND a2$ = "{" THEN matlist_input = 2: GOTO done
|
||
|
GOTO done
|
||
|
END IF
|
||
|
|
||
|
IF material_input THEN
|
||
|
IF material_input = 2 THEN
|
||
|
IF a2$ = ";" THEN
|
||
|
'do nothing
|
||
|
ELSEIF a2$ = "}" THEN
|
||
|
material_input = 0
|
||
|
ELSE
|
||
|
N = material_n
|
||
|
IF N = 1 THEN MATERIAL(MATERIAL).Diffuse.R = value#
|
||
|
IF N = 2 THEN MATERIAL(MATERIAL).Diffuse.G = value#
|
||
|
IF N = 3 THEN MATERIAL(MATERIAL).Diffuse.B = value#
|
||
|
IF N = 4 THEN MATERIAL(MATERIAL).Diffuse.A = value#
|
||
|
IF N = 5 THEN MATERIAL(MATERIAL).Diffuse.Intensity = value# / 100
|
||
|
IF N = 6 THEN MATERIAL(MATERIAL).Specular.R = value#
|
||
|
IF N = 7 THEN MATERIAL(MATERIAL).Specular.G = value#
|
||
|
IF N = 8 THEN MATERIAL(MATERIAL).Specular.B = value#
|
||
|
IF N = 9 THEN MATERIAL(MATERIAL).Specular.A = value#
|
||
|
IF N = 10 THEN MATERIAL(MATERIAL).Specular.Intensity = MATERIAL(MATERIAL).Diffuse.Intensity
|
||
|
|
||
|
'if texture_image
|
||
|
material_n = N + 1
|
||
|
|
||
|
END IF
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF material_input = 1 AND a2$ = "{" THEN material_input = 2: material_n = 1: GOTO done
|
||
|
GOTO done
|
||
|
END IF
|
||
|
|
||
|
IF texco_input THEN
|
||
|
IF texco_input = 4 THEN
|
||
|
IF a2$ = ";" THEN
|
||
|
IF last_a2$ = ";" THEN
|
||
|
texco_input = 0
|
||
|
GOTO finished
|
||
|
END IF
|
||
|
plane = plane + 1: IF plane = 3 THEN plane = 1
|
||
|
ELSEIF a2$ = "," THEN
|
||
|
vertex = vertex + 1
|
||
|
ELSE
|
||
|
IF plane = 1 THEN
|
||
|
TEXCO_TX(vertex) = value#
|
||
|
ELSE
|
||
|
TEXCO_TY(vertex) = value#
|
||
|
END IF
|
||
|
END IF
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF texco_input = 3 THEN
|
||
|
IF a2$ = ";" THEN texco_input = 4: plane = 1: vertex = 1
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF texco_input = 2 THEN
|
||
|
'vertices already known
|
||
|
texco_input = 3
|
||
|
GOTO done
|
||
|
END IF
|
||
|
IF texco_input = 1 THEN
|
||
|
IF a2$ = "{" THEN texco_input = 2
|
||
|
GOTO done
|
||
|
END IF
|
||
|
|
||
|
GOTO done
|
||
|
END IF
|
||
|
|
||
|
'mode switch?
|
||
|
IF a2$ = "MESHTEXTURECOORDS" THEN texco_input = 1: PRINT "[Texture Coordinates]";: GOTO done
|
||
|
IF a2$ = "MESHNORMALS" THEN normals_input = 1: mesh_input = 1: face_input = 0: PRINT "[Normals]";: GOTO done
|
||
|
IF a2$ = "MESH" THEN mesh_input = 1: PRINT "[Mesh Vertices & Faces]";: GOTO done
|
||
|
IF a2$ = "MESHMATERIALLIST" THEN matlist_input = 1: PRINT "[Face Material Indexes]";: GOTO done
|
||
|
IF LEFT$(a2$, 9) = "MATERIAL " THEN
|
||
|
material_input = 1: MATERIAL = MATERIAL + 1
|
||
|
MATERIAL(MATERIAL).Texture = 0: MATERIAL(MATERIAL).Texture_Image = texture_image
|
||
|
PRINT "[Material]";: GOTO done
|
||
|
END IF
|
||
|
done:
|
||
|
|
||
|
progress = progress + 1: IF progress > 5000 THEN PRINT ".";: progress = 0
|
||
|
|
||
|
IF a = ASC_SEMICOLON THEN
|
||
|
last_a2$ = a2$
|
||
|
ELSE
|
||
|
IF LEN(last_a2$) THEN last_a2$ = ""
|
||
|
END IF
|
||
|
|
||
|
LOOP
|
||
|
finished:
|
||
|
'change texture coords (with are organised per vertex to be organised by face side
|
||
|
'that way one vertex can share multiple materials without duplicating the vertex
|
||
|
PRINT "[Attaching Texture Coordinates to Face Cornders]";
|
||
|
f = 1
|
||
|
DO UNTIL f > FACES
|
||
|
v = FACE(f).V1.V + 1: FACE(f).V1.TX = TEXCO_TX(v): FACE(f).V1.TY = TEXCO_TY(v)
|
||
|
v = FACE(f).V2.V + 1: FACE(f).V2.TX = TEXCO_TX(v): FACE(f).V2.TY = TEXCO_TY(v)
|
||
|
v = FACE(f).V3.V + 1: FACE(f).V3.TX = TEXCO_TX(v): FACE(f).V3.TY = TEXCO_TY(v)
|
||
|
f = f + 1
|
||
|
LOOP
|
||
|
PRINT
|
||
|
PRINT "Model loaded!"
|
||
|
|
||
|
DEFSNG A-Z
|
||
|
|
||
|
END SUB
|
||
|
|
||
|
FUNCTION GLH_RGB%& (r AS SINGLE, g AS SINGLE, b AS SINGLE)
|
||
|
DONT_USE_GLH_COL_RGBA(1) = r
|
||
|
DONT_USE_GLH_COL_RGBA(2) = g
|
||
|
DONT_USE_GLH_COL_RGBA(3) = b
|
||
|
DONT_USE_GLH_COL_RGBA(4) = 1
|
||
|
GLH_RGB = _OFFSET(DONT_USE_GLH_COL_RGBA())
|
||
|
END FUNCTION
|
||
|
|
||
|
FUNCTION GLH_RGBA%& (r AS SINGLE, g AS SINGLE, b AS SINGLE, a AS SINGLE)
|
||
|
DONT_USE_GLH_COL_RGBA(1) = r
|
||
|
DONT_USE_GLH_COL_RGBA(2) = g
|
||
|
DONT_USE_GLH_COL_RGBA(3) = b
|
||
|
DONT_USE_GLH_COL_RGBA(4) = a
|
||
|
GLH_RGBA = _OFFSET(DONT_USE_GLH_COL_RGBA())
|
||
|
END FUNCTION
|
||
|
|
||
|
|
||
|
|