Compare commits

...

262 Commits

Author SHA1 Message Date
mrq
2601afb5f3 experimental support for parsing from a float16 mesh (or a float32-quantized-as-ushort mesh) 2023-10-26 13:22:47 -05:00
Luke Benstead
0efe4c6cef Add missing defines 2023-10-19 22:26:13 +01:00
Luke Benstead
744dfb32f7 Merge branch 'fix-glshort-uv-read' into 'master'
Convert GL_SHORT to proper float on conversion

See merge request simulant/GLdc!109
2023-09-26 18:51:30 +00:00
Spencer Elliott
79172452f2 Convert GL_SHORT to proper float on conversion 2023-09-26 18:51:29 +00:00
Luke Benstead
420e2d75f2 Merge branch 'fix-glulookat-alignment' into 'master'
Fixed alignment for matrix passed into UploadMatrix4x4 in gluLookAt

See merge request simulant/GLdc!108
2023-09-20 15:47:38 +00:00
Spencer Elliott
202f546848 Fixed alignment for matrix passed into UploadMatrix4x4 in gluLookAt 2023-09-20 10:18:55 -05:00
Luke Benstead
d054dde785 Fix paletted texture glitch 2023-09-12 21:11:05 +01:00
Luke Benstead
00b4468928 Remove unused function 2023-09-11 20:42:09 +01:00
Luke Benstead
f0d799d14f Merge branch 'texture-refactor' into 'master'
Drastically refactor glTexImage2D

See merge request simulant/GLdc!107
2023-09-11 19:39:03 +00:00
Luke Benstead
1bf8554926 More erquirements 2023-09-11 20:34:18 +01:00
Luke Benstead
9bc6da9fba Add some requirements 2023-09-11 19:55:26 +01:00
Luke Benstead
a1536cba44 Add dependency 2023-09-11 17:31:08 +01:00
Luke Benstead
3eee140add Fix stage 2023-09-11 17:29:59 +01:00
Luke Benstead
43d64a4957 Fix twiddling issues 2023-09-11 17:27:04 +01:00
Luke Benstead
951ece6d19 Add test job to CI 2023-09-11 17:25:47 +01:00
Luke Benstead
61e5a7a2a6 More twiddling work 2023-09-10 19:41:25 +01:00
Luke Benstead
3308a57e59 Implement defragmenting the memory 2023-09-08 17:49:46 +01:00
Luke Benstead
db9e1cd424 Fall back to unaligned if there's no more aligned spaced 2023-09-08 09:13:33 +01:00
Luke Benstead
6eb079228e Fix infinite loop 2023-09-06 21:01:37 +01:00
Luke Benstead
7ce01ad93f Fix up paletted textures 2023-09-06 08:01:01 +01:00
Luke Benstead
12bd6f474f Fix issues with the allocator 2023-09-06 07:59:40 +01:00
Luke Benstead
e5a4f4f716 Continue fixing up paletted texture issues 2023-09-03 21:12:11 +01:00
Luke Benstead
4d39e19ed5 Start repairing paletted textures 2023-09-02 21:10:42 +01:00
Luke Benstead
49a0e103cb Fix up CI 2023-09-01 20:34:29 +01:00
Luke Benstead
9cedc81850 Fix broken merge 2023-09-01 20:29:24 +01:00
Luke Benstead
0e31aa3d27 Tweak 2023-09-01 20:25:27 +01:00
Luke Benstead
5e7b33797d Perf improvements and fixes 2023-09-01 20:25:27 +01:00
Luke Benstead
b19b9d498a Clean up the allocator code 2023-09-01 20:25:21 +01:00
Luke Benstead
36de063756 Allow configuring automatic texture twiddling in glKosInitEx
Defaults to enabled.
2023-09-01 20:23:55 +01:00
Luke Benstead
246cb997da Add optional dcprof to prof_texture_upload 2023-09-01 20:23:55 +01:00
Luke Benstead
cfbaea4a46 Don't calculate things twice 2023-09-01 08:52:01 +01:00
Luke Benstead
4b47f6878f Remove yalloc 2023-09-01 08:34:48 +01:00
Luke Benstead
3248499d5a Switch to the new allocator 2023-08-31 21:21:14 +01:00
Luke Benstead
fd9a9d1c25 Merge commit 'f49a98ab543b1be0049e07456fb23022435ba450' into texture-refactor 2023-08-31 20:49:42 +01:00
Luke Benstead
f49a98ab54 Fix allocate and free 2023-08-31 20:49:34 +01:00
Luke Benstead
f278777c0e WIP: Start implementing new allocator 2023-08-31 08:47:00 +01:00
Luke Benstead
34173d926c Drastically refactor glTexImage2D 2023-08-31 08:47:00 +01:00
Luke Benstead
77531ca347 Drastically refactor glTexImage2D 2023-08-26 20:34:11 +01:00
Luke Benstead
a05e1b01fa Make glGenerateMipmap the function, and EXT the alias 2023-07-26 20:33:12 +01:00
Luke Benstead
3dcbbdbde6 Add logging 2023-06-09 20:35:00 +01:00
Luke Benstead
92ee4f616d Set mode to PAL@50 if it's a European console without VGA 2023-06-06 21:05:52 +01:00
Luke Benstead
e7574bca1d Fix issues with GL_QUADS 2023-05-31 18:27:17 +01:00
Luke Benstead
026bdeff09 Fix infuriating memory corruption bug 2023-05-20 07:47:39 +01:00
Luke Benstead
f6713bc778 Speed up the software renderer 2023-05-20 07:45:45 +01:00
Luke Benstead
5865d57384 Wait for the store queues to finish when we've uploaded everything 2023-05-20 07:45:16 +01:00
Luke Benstead
1e3896e699 Clean up 2023-05-20 07:44:55 +01:00
Luke Benstead
bd47f333d6 Add more assertions 2023-05-20 07:43:57 +01:00
Luke Benstead
e57b503355 Fix memory errors 2023-05-18 16:44:11 +01:00
Luke Benstead
d81472ef57 Liberally assert stuff 2023-05-17 20:39:58 +01:00
Luke Benstead
462eb40d7a Fix bugs in texture deletion 2023-05-17 20:39:49 +01:00
Luke Benstead
c4c0bf4239 Fix an off-by-one error 2023-05-17 20:39:27 +01:00
Luke Benstead
9037d157d5 Clean up 2023-05-17 20:38:21 +01:00
Luke Benstead
52a0215ed8 Make sure we initialize texture 0. We don't actually use it yet
(binding zero disables texturing) but I believe the spec says that
texture 0 is the "default texture" and is an actual texture object.
2023-05-17 20:36:59 +01:00
Luke Benstead
a5891056db Many bug fixes and optimisations 2023-05-16 13:31:44 +01:00
Luke Benstead
9cffe14ad6 Clean up aligned vector 2023-05-12 20:51:36 +01:00
Luke Benstead
e683b8becb Optimisations 2023-05-11 20:00:13 +01:00
Luke Benstead
cba2fb7ceb Fix a memory corruption issue 2023-05-11 15:22:46 +01:00
Luke Benstead
c754c5c338 Ensure RelWithDebInfo builds use release flags + debugging 2023-05-11 15:22:27 +01:00
Luke Benstead
452cda5a3b Fix backface culling 2023-04-28 19:49:01 +01:00
Luke Benstead
9e1b1bc40a Merge branch 'clipping-rewrite-for-the-last-time-ffs' into 'master'
Restructure clipping to be much MUCH faster in the visible case

See merge request simulant/GLdc!105
2023-04-26 20:00:17 +00:00
Luke Benstead
0f65eab86a Much faster clipping 2023-04-26 20:50:43 +01:00
Luke Benstead
1a678d2c8d Undo some bad changes 2023-04-23 21:00:01 +01:00
Luke Benstead
0923b5c601 Further optimisations 2023-04-23 20:16:15 +01:00
Luke Benstead
2ec7055547 Optimisations 2023-04-23 07:44:09 +01:00
Luke Benstead
9cc52a01fe Better clipping 2023-04-22 20:47:45 +01:00
Luke Benstead
095ebf2790 Fix final bug 2023-04-22 11:37:42 +01:00
Luke Benstead
baa275b41b Fix a bunch of issues with clipping (almost working) 2023-04-21 20:38:21 +01:00
Luke Benstead
72c375f87c Fix some things 2023-04-21 11:39:37 +01:00
Luke Benstead
e54494e995 More clipping work 2023-04-20 20:45:59 +01:00
Luke Benstead
c5ce81a38d WIP: Restructure clipping to be much MUCH faster in the visible case
This currently only works with triangles, anything more and it crashes
due to me not queuing subsequent vertices in the strip correctly
2023-04-19 20:57:44 +01:00
Luke Benstead
34448939a4 Merge branch 'update-cubes-cmakelists' into 'master'
Update cubes sample + cmakelists

See merge request simulant/GLdc!104
2023-04-17 18:24:56 +00:00
Dave
b6249e9ca4 Update README 2023-04-17 19:35:06 +02:00
Dave
1a181f702c Update CMakeLists with CXX flags (Debug and Release) 2023-04-17 19:34:56 +02:00
Dave
3b53691e4b Change float colors to GLubyte in cubes sample 2023-04-17 19:33:59 +02:00
Luke Benstead
25d215dad3 Add some compiler flags for lolz 2023-04-11 20:46:44 +01:00
Luke Benstead
307d371c55 Various store queue shinanigans 2023-04-11 20:46:31 +01:00
Luke Benstead
4ad58bea89 Optimise glLoadMatrixf 2023-04-11 20:46:12 +01:00
Luke Benstead
8e60b18f29 Merge branch 'add-new-cubes-sample' into 'master'
Add new cubes sample

See merge request simulant/GLdc!103
2023-04-08 20:32:18 +00:00
David Reichelt
190b4ecfb7 Add include for printf 2023-04-08 20:07:21 +00:00
David Reichelt
a4b778063a Make sure ZNEAR_CLIPPING_ENABLED is defined in software renderer 2023-04-08 20:00:33 +00:00
Dave Reichelt
df9a12bbd6 Added new cubes sample
- A button toggles between glDrawElements and glDrawArrays
- B button toggles glBlend
- Start quits the sample
- Every 10 seconds a log with stats will be sent to the terminal
2023-04-08 21:42:03 +02:00
Luke Benstead
6ee9a823c1 Don't update lights unnecessarily 2023-03-23 20:01:41 +00:00
Luke Benstead
0c5f941098 Optimise nearz clipping 2023-03-17 20:40:55 +00:00
Luke Benstead
300f2a611e Optimise state management 2023-03-17 20:40:45 +00:00
Luke Benstead
e810d2567d Merge commit 'e5c6fefcd92cb6e877e8501c4b43cbf75460409d' 2023-03-16 21:24:22 +00:00
Luke Benstead
e5c6fefcd9 Optimisations 2023-03-16 21:24:12 +00:00
Luke Benstead
0cf006ebce Merge branch 'bug-fixes' into 'master'
Fix elf extension and compilation with GCC4.7

See merge request simulant/GLdc!100
2023-03-07 21:40:54 +00:00
Luke Benstead
8789d6557e Huge refactor of internal state 2023-03-07 21:27:48 +00:00
Luke Benstead
8beb295c6b Refactor state management 2023-03-07 10:19:09 +00:00
Luke Benstead
c195d471e1 Faster memcpy 2023-03-06 14:05:14 +00:00
Luke Benstead
be4c1bc14c Add missing header 2023-03-06 13:54:31 +00:00
Luke Benstead
a9f3e3a744 Fix alignments 2023-03-06 13:44:17 +00:00
Luke Benstead
f0a3465486 Use Moops memcpy 2023-03-05 21:16:12 +00:00
Luke Benstead
b08bbebf12 Mipmap fix 2023-03-05 20:26:15 +00:00
falco
e27c276daa Fixed poly/tri/quadmarks to build with GCC12
"start" is a reserved symbol within KOS, per crt1.s. Not sure why the old toolchains let us use this symbol name elsewhere, but the new GCC12 toolchain rightfully complains about duplicate symbols.

- Renamed "start" timestamp to "begin."
2023-03-04 17:35:17 -06:00
Colton Pawielski
5bb2691b91 Change CMakeLists.txt to add -mfsrra and -mfsca only if supported by compiler
GCC4.7 does not support these flags and cause a failure to build
2023-03-04 16:13:44 -06:00
Colton Pawielski
ac6914398c Fix .elf extension on C example executables 2023-03-04 16:11:11 -06:00
Colton Pawielski
8481fd05cc Add dcbuild & pcbuild folders to .gitignore 2023-03-04 16:10:34 -06:00
Luke Benstead
19288918f0 Merge branch 'Declare_glFogiv' into 'master'
declare glFogiv()

See merge request simulant/GLdc!95
2023-02-02 11:58:35 +00:00
Luke Benstead
8fff6ee1aa Treat GL_CLAMP_TO_EDGE the same as GL_CLAMP 2022-12-09 20:17:46 +00:00
Luke Benstead
ac86504549 Clean up 2022-12-03 20:01:43 +00:00
Luke Benstead
d78c6275bb Increase tri-strip length 2022-12-03 14:00:24 +00:00
Luke Benstead
69a2310a3c Default to small culling to avoid artifacts 2022-12-03 13:46:08 +00:00
Luke Benstead
5296f5c79c Optimise perspective divide assuming W is always positive 2022-11-05 20:28:24 +00:00
Luke Benstead
aa875ae4d1 Fix compiler flags 2022-11-04 19:34:42 +00:00
Luke Benstead
7db15a0e03 Fix PC build 2022-11-04 19:25:50 +00:00
Luke Benstead
b6593acc83 Switches instead of if ladders 2022-11-04 19:24:12 +00:00
Luke Benstead
8ca70a2920 Initialize submission target on boot to save runtime cost 2022-11-04 19:23:50 +00:00
Luke Benstead
4d8c507706 Fix a bug where glXPointer functions would do unnecessary work 2022-11-04 19:23:06 +00:00
Luke Benstead
a248f3a50c Faster inversion 2022-11-03 20:24:38 +00:00
Luke Benstead
6be3e6185d Faster inversion 2022-09-14 19:20:24 +01:00
Luke Benstead
3caaf798e7 Undo double transform 2022-08-25 21:25:52 +01:00
Luke Benstead
0b62ac8673 Clean ups and optimisations 2022-08-25 21:24:08 +01:00
Luke Benstead
4edf8ce04d Use the direct texture path for vbuffer uploads 2022-08-25 20:01:54 +01:00
Luke Benstead
c793e1f35d Don't submit empty lists 2022-08-24 20:31:55 +01:00
Luke Benstead
9b9db31f30 Merge branch 'super-clip' into 'master'
Super clip

See merge request simulant/GLdc!99
2022-06-13 19:26:55 +00:00
Luke Benstead
9d9a502e96 Remove old clipping 2022-06-13 20:16:46 +01:00
Luke Benstead
3d69003c5f Allow disabling near-z 2022-06-13 20:16:37 +01:00
Luke Benstead
99ae70a72b Make the software implementation use the same clipping code 2022-06-13 20:06:04 +01:00
Luke Benstead
6fb15ee4c7 Fix some winding issues 2022-06-13 20:05:54 +01:00
Luke Benstead
b17104afea Add a missing header 2022-06-13 20:05:39 +01:00
Luke Benstead
16f6100afa Fix issues and optimise 2022-06-12 19:53:26 +01:00
Luke Benstead
4827fd4c5b Fix various clipping glitches 2022-06-11 21:27:09 +01:00
Luke Benstead
53c54997c3 Fix a number of issues! 2022-06-10 20:27:21 +01:00
Luke Benstead
68c6936b25 Add nehe10 sample 2022-06-10 20:26:51 +01:00
Luke Benstead
dbb94d0cb9 Move clipping into list submission 2022-06-09 13:07:51 +01:00
Luke Benstead
193f0bdc49 Cleanup 2022-05-21 20:16:50 +01:00
Luke Benstead
9a50917062 Fix rgba vs argb inversion 2022-05-21 20:16:34 +01:00
Luke Benstead
83e325ab3c Fix CMake 32bit issues 2022-05-21 20:16:26 +01:00
Luke Benstead
0060f48202 Fix compilation issues on PC vs DC 2022-05-21 20:16:12 +01:00
Luke Benstead
fe7f9cbed0 Fix crash when generating mipmaps on 4bpp textures 2022-05-07 12:57:45 +01:00
Luke Benstead
3d1f447af9 Merge branch 'paletted-textures' into 'master'
4BPP paletted textures and OES_compressed_paletted_texture support

See merge request simulant/GLdc!98
2022-05-04 20:05:24 +00:00
Luke Benstead
d0e6b56414 Restore validation of the internalFormat (even though it's unused) 2022-05-04 21:00:15 +01:00
Luke Benstead
dc69a81da1 Remove unused code. Various clean ups 2022-05-04 20:53:18 +01:00
Luke Benstead
411d4f0e4f Add a missing space 2022-05-04 20:45:21 +01:00
Luke Benstead
dd7bb47ffb Merge remote-tracking branch 'ozzyouzo/master' into paletted-textures 2022-05-04 20:39:39 +01:00
Luke Benstead
46605c6b1a Merge branch 'Avoid_gl_h_Function_is_not_a_prototype_warning' into 'master'
gl.h: avoid gcc warning "function declaration isn’t a prototype"

See merge request simulant/GLdc!97
2022-05-04 19:20:13 +00:00
OzzyOuzo
c48bbfe07c Fixed glMultMatrixf(...)
Added _glResetSharedPalettes
2022-05-03 16:12:27 +03:00
Luke Benstead
4e8ff2f8e4 Fix texture issues 2022-04-26 20:34:14 +01:00
T_chan
cd14a5ed11 gl.h: avoid gcc warning "function declaration isn’t a prototype" 2022-02-07 16:09:00 +00:00
Luke Benstead
6f2b4d8f9f Merge branch 'Add_missing_gl_h_defines' into 'master'
Add some missing gl.h defines for portability

See merge request simulant/GLdc!96
2022-02-07 15:48:26 +00:00
T_chan
2d63fdf30f Add some missing gl.h defines for portability 2022-02-07 15:36:16 +00:00
T_chan
3160fc517d declare glFogiv() 2022-02-02 09:22:23 +00:00
Luke Benstead
774a956012 Merge branch 'refactor_nehe08' into 'master'
refactor nehe08 slightly

See merge request simulant/GLdc!94
2022-02-01 09:00:46 +00:00
T_chan
bd507f38bd refactor nehe08 slightly 2022-02-01 08:48:31 +00:00
Luke Benstead
4ad5f00538 Merge branch 'Add_gluBuild2DMipmaps' into 'master'
Add gluBuild2DMipmaps()

See merge request simulant/GLdc!93
2022-02-01 08:28:40 +00:00
T_chan
53eb2e2a51 Add gluBuild2DMipmaps() 2022-02-01 07:25:54 +00:00
Luke Benstead
5be561ce4f Merge branch 'Correct_Sample_Files_Paths' into 'master'
samples: correct image  paths & include <math.h>

See merge request simulant/GLdc!92
2022-01-31 20:47:56 +00:00
T_chan
fdac490e34 samples: correct image paths & include <math.h> 2022-01-31 16:59:05 +00:00
Luke Benstead
f5436fd31b Merge branch 'Regroup_BMP_Loading' into 'master'
regroup the BMP file loading into 1 file, and correct some types that give...

See merge request simulant/GLdc!87
2022-01-31 10:30:26 +00:00
T_chan
ae3ebe2e5c regroup the BMP file loading into 1 file, and correct some types that give... 2022-01-31 10:30:26 +00:00
Luke Benstead
d7d8f4c4f1 Merge branch 'Samples_Make_Romdisk_Conditional' into 'master'
Include romdisk only if target is dreamcast

See merge request simulant/GLdc!86
2022-01-31 10:06:02 +00:00
Luke Benstead
12080967c2 Merge branch 'Fix_depth_funcs_ortho' into 'master'
fix depth_funcs_ortho - show blue and green quads

See merge request simulant/GLdc!88
2022-01-31 10:05:03 +00:00
Luke Benstead
80ca380a22 Merge branch 'Correct_Blend_Test' into 'master'
merge of blend_test and lerabot_blend_test, addition of 1 case, and...

See merge request simulant/GLdc!89
2022-01-31 10:04:50 +00:00
T_chan
ab627b5ef5 merge of blend_test and lerabot_blend_test, addition of 1 case, and... 2022-01-31 10:04:50 +00:00
Luke Benstead
bc422f1f47 Merge branch 'Correct_lerabot01' into 'master'
dont put objects on the far plane

See merge request simulant/GLdc!90
2022-01-31 10:04:24 +00:00
Luke Benstead
b3066f991c Merge branch 'Add_glGetTexImage_stub' into 'master'
Add glGetTexImage stub for portability

See merge request simulant/GLdc!91
2022-01-31 10:03:56 +00:00
T_chan
621982d14e Add glGetTexImage stub for portability 2022-01-31 08:29:00 +00:00
T_chan
23419bf57c dont put objects on the far plane 2022-01-26 19:46:31 +00:00
T_chan
7abd878e93 AS-IS, depth_funcs_ortho only displays 1 red quad. With the fix, the 2 other quads (blue, green) become visible again 2022-01-25 20:47:40 +00:00
T_chan
0c8e11c02a Include romdisk only if target is dreamcast 2022-01-25 14:41:55 +00:00
Luke Benstead
9506237c47 Merge branch 'Solve_Warnings' into 'master'
Solve some warnings from the compilation

See merge request simulant/GLdc!83
2022-01-25 13:44:09 +00:00
Luke Benstead
e2da03ac74 Merge branch 'Remove_mipmapping_from_Nehe06' into 'master'
Remove mipmapping from Nehe06

See merge request simulant/GLdc!84
2022-01-25 13:43:49 +00:00
Luke Benstead
705cb30be8 Merge branch 'Solve_Sample_Warnings' into 'master'
solve 4 warnings about printf & long unsigned values vs %d

See merge request simulant/GLdc!85
2022-01-25 13:43:30 +00:00
T_chan
37e407d032 solve 4 warnings about printf & long unsigned values vs %d 2022-01-25 13:35:24 +00:00
T_chan
f5b63bfc97 Remove mipmapping from Nehe06 2022-01-23 13:07:58 +00:00
T_chan
b1508be822 Solve some warnings from the compilation 2022-01-20 22:42:08 +00:00
Luke Benstead
4ad2841809 Merge branch 'Add_glTexCoord1f_functions' into 'master'
Add glTexCoord1f() and glTexCoord1fv()

See merge request simulant/GLdc!80
2022-01-19 08:05:59 +00:00
Luke Benstead
cfbd126f58 Merge branch 'Add_GL_LINE_SMOOTH' into 'master'
Add GL_LINE_SMOOTH to increase portability

See merge request simulant/GLdc!82
2022-01-19 08:05:31 +00:00
Luke Benstead
ea44f21c04 Merge branch 'T_chan-master-patch-83707' into 'master'
remove duplicate defines from gl.h

See merge request simulant/GLdc!81
2022-01-19 08:05:18 +00:00
T_chan
fb2e8d7d7e Update include/GL/gl.h 2022-01-19 06:55:33 +00:00
T_chan
72b115659a remove duplicate defines from gl.h 2022-01-19 06:50:11 +00:00
T_chan
9b6c2bbb21 Add glTexCoord1f() and glTexCoord1fv() 2022-01-18 21:40:31 +00:00
Luke Benstead
f9af9af567 Merge branch 'Add_glPolygonMode_Stub' into 'master'
add glPolygonMode() stub

See merge request simulant/GLdc!79
2022-01-18 21:38:31 +00:00
Luke Benstead
8d51579870 Merge branch 'Add_Stencil_Functions_Stubs' into 'master'
Add stubs for Stencil functions glStencilFunc() and glStencilOp()

See merge request simulant/GLdc!78
2022-01-18 21:37:56 +00:00
T_chan
50aee8a92c add glPolygonMode() stub 2022-01-18 21:28:07 +00:00
T_chan
66d87fb845 Add stubs for Stencil functions glStencilFunc() and glStencilOp() 2022-01-18 20:29:27 +00:00
Luke Benstead
6802f64725 Merge branch 'Add_PixelStore_parameters' into 'master'
Add PixelStore parameters for Read/DrawPixels to increase compatibility

See merge request simulant/GLdc!77
2022-01-18 19:25:56 +00:00
Luke Benstead
11860ba6e1 Merge branch 'add_glGetTexParameterfv_stub' into 'master'
Add glGetTexParameterfv() stub to increase compatibility

See merge request simulant/GLdc!76
2022-01-18 19:25:39 +00:00
Luke Benstead
3b320bf874 Merge branch 'add_glTexParameterf' into 'master'
expose and correct glTexParameterf()

See merge request simulant/GLdc!75
2022-01-18 19:25:20 +00:00
Luke Benstead
fbf322f470 Merge branch 'add_glColor4ubv' into 'master'
Add glColor4ubv() to increase compatibility of GLdc

See merge request simulant/GLdc!74
2022-01-18 19:25:02 +00:00
Luke Benstead
482ec8b270 Merge branch 'add_GLclampd' into 'master'
add GLclampd to increase compatibility of GLdc

See merge request simulant/GLdc!73
2022-01-18 19:24:11 +00:00
T_chan
fbe310f8d5 Add PixelStore parameters for Read/DrawPixels to increase compatibility 2022-01-18 18:09:44 +00:00
T_chan
d594eff3a6 Add glGetTexParameterfv() stub to increase compatibility 2022-01-18 17:38:14 +00:00
T_chan
0d60b318da expose and correct glTexParameterf() 2022-01-18 17:23:30 +00:00
T_chan
d9a2ed7892 Add glColor4ubv() to increase compatibility of GLdc 2022-01-18 17:06:26 +00:00
T_chan
a7762aa965 add GLclampd to increase compatibility of GLdc 2022-01-18 16:51:31 +00:00
OzzyOuzo
1a456cb1a7 16bit palette color format support, extended 64 shared palette slots (4bpp), GL_OES_compressed_paletted_texture support
GL_ERROR generated when texture size > 1024
2021-12-03 09:32:53 +02:00
OzzyOuzo
8caee68df5 added _glFreePaletteSlots(..) 2021-11-30 19:23:49 +02:00
OzzyOuzo
148962254a 4bpp texture palette support, modified paletted_pcx sampled (USE_16C_PALETTE) 2021-11-18 12:04:46 +02:00
OzzyOuzo
37110ba47f 4bpp texture palette support (GL_RGBA8 pal components), modified paletted_pcx sample (USE_16C_PALETTE) 2021-11-18 11:59:37 +02:00
Luke Benstead
b710a619d5 Fix issues with bilinear mipmapping 2021-10-25 19:04:58 +01:00
Luke Benstead
e225f54386 Fix bug when glVertexPointer etc. is called without client state enabled 2021-10-02 20:01:44 +01:00
Luke Benstead
5df2190536 Fix various bugs with non-fastpath rendering 2021-10-02 14:43:23 +01:00
Luke Benstead
458fb52efb Merge branch 'fix-ci' into 'master'
Fix ci

See merge request simulant/GLdc!72
2021-10-01 20:20:29 +00:00
Luke Benstead
cef1e852f4 Fix ci 2021-10-01 20:20:29 +00:00
Luke Benstead
7d82649a62 Be sure to restore the fast path flag in glEnd 2021-10-01 21:02:13 +01:00
Luke Benstead
ecc957bcbd Merge branch 'master' into 'master'
Avoid the need to hard-reset the Dreamcast to exit the samples - use the start button in all samples

See merge request simulant/GLdc!71
2021-10-01 19:57:33 +00:00
T_chan
830a985606 Avoid the need to hard-reset the Dreamcast to exit the samples - use the start button in all samples 2021-10-01 19:57:32 +00:00
Luke Benstead
6184208598 Don't include platform.h from aligned_vector.h 2021-09-18 17:40:10 +01:00
Luke Benstead
e26fae6d2e Remove debug logging 2021-09-18 14:37:28 +01:00
Luke Benstead
dd16530a1f Fix an assertion in debug, and building on PC 2021-09-18 14:36:47 +01:00
Luke Benstead
cf996b9e80 Add tri and quad fast paths 2021-09-14 19:36:42 +01:00
Luke Benstead
7992c89758 Fix perf hit 2021-09-14 09:20:00 +01:00
Luke Benstead
9c2907e41d Small optimisation 2021-09-13 19:57:46 +01:00
Luke Benstead
4ee9c3ee64 More optimisations 2021-09-13 19:35:53 +01:00
Luke Benstead
adce2c7538 Perf tweaks 2021-09-13 12:57:52 +01:00
Luke Benstead
52ff506397 Only recalc the fast path when pointers change 2021-09-13 10:40:25 +01:00
Luke Benstead
66d09e7d77 Error cleanup and immediate mode perf improvements 2021-09-13 10:29:04 +01:00
Luke Benstead
4adc49cd40 Optimisations 2021-09-12 15:04:52 +01:00
Luke Benstead
cb96769074 Fix incorrect usage of memset 2021-09-04 13:36:59 +01:00
Luke Benstead
3332dfa74a Handle running out of PVR memory correctly 2021-09-04 12:14:31 +01:00
Luke Benstead
efc75db05c Merge branch 'master' into 'master'
Enable building for sub-architecture naomi.

See merge request simulant/GLdc!70
2021-07-05 19:27:29 +00:00
T_chan
08eebfccc0 Enable building for sub-architecture naomi.
Tested with examples nehe02, nehe06, nehe08 - displays the same as on Dreamcast.
2021-07-05 19:12:10 +00:00
Luke Benstead
fc947c49f8 Performance improvements 2021-05-25 20:40:43 +01:00
Luke Benstead
f736332eb8 Always make sure we send opaque polys with one/zero blending 2021-05-23 20:58:29 +01:00
Luke Benstead
7376d3e625 Tweak toolchain fix 2021-05-23 13:25:52 +01:00
Luke Benstead
5d4f83c53a Tweak toolchain fix 2021-05-23 13:24:29 +01:00
Luke Benstead
3975c68c5e Try to fix toolchain file on Windows 2021-05-23 13:21:08 +01:00
Luke Benstead
a79c1dd753 Set the right depth mode when autosort is on 2021-05-23 13:19:54 +01:00
Luke Benstead
cde0abd18d Force the correct depth and blend modes with PT polys 2021-05-23 13:15:07 +01:00
Luke Benstead
0789ea99b3 Disable fast mode by default 2021-05-23 13:06:11 +01:00
Luke Benstead
f0383f8e1c Remove broken check 2021-05-16 20:33:49 +01:00
Luke Benstead
5ea4313d59 Fix software renderer 2021-05-14 21:58:54 +01:00
Luke Benstead
840ac7f0cd Merge branch 'master' into 'master'
Fix memory leaks in samples

See merge request simulant/GLdc!69
2021-05-14 14:11:03 +00:00
Colton Pawielski
3d6c756ab7 Fix memory leaks in samples
Add free to end of LoadGLTextures() to release image1 after use.
2021-05-14 08:57:10 -04:00
Luke Benstead
06529d4fe7 Perf tweaks 2021-05-08 14:38:55 +01:00
Luke Benstead
cfefce44a6 Add nehe20 sample 2021-05-08 14:17:57 +01:00
Luke Benstead
a98f22e3c9 Remove old Makefiles 2021-05-08 13:15:18 +01:00
Luke Benstead
cb9d699576 Use invW as the Z axis (abandon standards compliance for speed) 2021-05-01 14:32:16 +01:00
Luke Benstead
0a8d43d47b Add nehe08 sample 2021-04-30 20:47:33 +01:00
Luke Benstead
e67f1fb8f9 Don't transform the vertex again incorrectly. Optimise 2021-04-30 07:58:57 +01:00
Luke Benstead
d05c5b8353 Remove incorrect warning 2021-04-30 07:52:12 +01:00
Luke Benstead
fcbb6418d2 Perf improvements 2021-04-26 16:16:25 +01:00
Luke Benstead
5fc77887d0 Remove unnecessary branches 2021-04-25 15:27:04 +01:00
Luke Benstead
16243acd7b More immediate mode optimisation 2021-04-25 14:21:09 +01:00
Luke Benstead
1b6f543fab Slight optimisation 2021-04-25 13:33:24 +01:00
Luke Benstead
40678836e0 Refactor viewport handling 2021-04-25 13:05:56 +01:00
Luke Benstead
57bb8c65c5 Fix artifact path 2021-04-24 11:31:11 +01:00
Luke Benstead
22680e8cbd Store the release artifacts in CI 2021-04-23 09:11:13 +01:00
Luke Benstead
1f42838992 Fix incorrect glColorPointer stride 2021-04-23 09:09:25 +01:00
Luke Benstead
28c14fdb0e Add fast path for glDrawElements 2021-04-22 17:48:15 +01:00
Luke Benstead
bb53dad90d Merge remote-tracking branch 'origin/master' 2021-04-21 21:31:21 +01:00
Luke Benstead
a7858d1f00 Merge branch 'batched-arrays' into 'master'
New Fast Path

See merge request simulant/GLdc!68
2021-04-21 16:23:43 +00:00
Luke Benstead
df2d7a210c New Fast Path 2021-04-21 16:23:43 +00:00
Luke Benstead
5a9b7bb37e Force inline aligned vector functions 2021-04-20 16:49:00 +01:00
Luke Benstead
ea25251944 Optimisations 2021-04-20 16:08:58 +01:00
Luke Benstead
faf24ac61d Small optimisations 2021-04-20 09:07:14 +01:00
Luke Benstead
b6a5ac6ce6 Optimisation in aligned_vector_extend 2021-04-19 21:29:19 +01:00
Luke Benstead
38c7967ae2 Clean up some things 2021-04-19 21:23:23 +01:00
Luke Benstead
165318ea76 Use MATH_fmac 2021-04-19 21:12:46 +01:00
Luke Benstead
1a849c8b1c Minor optimisation 2021-04-19 21:08:09 +01:00
Luke Benstead
a3c4aaac8f Don't set a zero zclip value 2021-04-19 20:51:22 +01:00
Luke Benstead
8977fbf6e2 Compile quadmark on PC 2021-04-19 20:43:56 +01:00
Luke Benstead
b480c0a01f Fix optimisations 2021-04-19 20:21:46 +01:00
Luke Benstead
eb35d607b9 Immediate mode performance optimisation 2021-04-19 10:53:08 +01:00
Luke Benstead
778e9c4e64 Optimise CompilePolyHeader 2021-04-18 21:50:41 +01:00
Luke Benstead
ce9f3677f6 Immediate mode optimisation 2021-04-18 21:33:23 +01:00
Luke Benstead
7bcbb86e80 Align to 32 byte 2021-04-18 13:57:28 +01:00
Luke Benstead
9ca68de427 Force 32-byte allocations 2021-04-18 13:57:00 +01:00
Luke Benstead
1172086378 Add debug logging and assertions to make sure we use sq_cpy aligned 2021-04-15 21:31:48 +01:00
Luke Benstead
fc1a18e002 Merge branch 'scissor' into 'master'
Implement glScissor correctly

See merge request simulant/GLdc!67
2021-04-14 20:41:10 +00:00
134 changed files with 18400 additions and 5416 deletions

2
.gitignore vendored
View File

@ -9,3 +9,5 @@ dc-build.sh
build/*
builddir/*
version.[c|h]
pcbuild/*
dcbuild/*

View File

@ -1,5 +1,6 @@
stages:
- build
- test
build:sh4-gcc:
stage: build
@ -8,16 +9,37 @@ build:sh4-gcc:
- source /etc/bash.bashrc
- mkdir builddir
- cd builddir
- cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/Dreamcast.cmake ..
- cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/Dreamcast.cmake -DCMAKE_BUILD_TYPE=Release ..
- make
- tar -zcf gldc.tar.gz libGLdc.a ../LICENSE ../README.md ../include
artifacts:
paths:
- builddir/gldc.tar.gz
build:x86-gcc:
stage: build
image: fedora:33
image: fedora:38
before_script:
- sudo dnf install -y cmake gcc gcc-c++ SDL2-devel.i686 glibc-devel.i686
- sudo dnf install -y cmake gcc gcc-c++ SDL2.i686 SDL2-devel.x86_64 glibc-devel glibc-devel.i686 SDL2-devel.i686 pkgconf-pkg-config.i686 pkgconf-pkg-config.x86_64
script:
- mkdir builddir
- cd builddir
- cmake ..
- cmake -DCMAKE_BUILD_TYPE=Release ..
- make
artifacts:
paths:
- builddir/tests/gldc_tests
test:x86-gcc:
stage: test
image: fedora:38
dependencies:
- build:x86-gcc
before_script:
- sudo dnf install -y cmake gcc gcc-c++ SDL2.i686 SDL2-devel glibc-devel pkgconf-pkg-config glibc-devel.i686 SDL2-devel.i686 pkgconf-pkg-config.i686
script:
- cd builddir/tests/
- SDL_VIDEODRIVER=dummy ./gldc_tests --junit-xml=report.xml
artifacts:
reports:
junit: builddir/tests/report.xml

View File

@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.9)
project(GLdc)
set(CMAKE_VERBOSE_MAKEFILE ON)
# set the default backend
if(PLATFORM_DREAMCAST)
set(BACKEND "kospvr" CACHE STRING "Backend to use")
@ -8,6 +10,9 @@ else()
set(BACKEND "software" CACHE STRING "Backend to use")
endif()
include(CheckIPOSupported)
check_ipo_supported(RESULT FLTO_SUPPORTED OUTPUT FLTO_ERROR)
# List of possible backends
set_property(CACHE BACKEND PROPERTY STRINGS kospvr software)
@ -17,20 +22,52 @@ string(TOUPPER ${BACKEND} BACKEND_UPPER)
add_definitions(-DBACKEND_${BACKEND_UPPER})
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
include_directories(include)
if(NOT PLATFORM_DREAMCAST)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
set(FIND_LIBRARY_USE_LIB32_PATHS true)
set(FIND_LIBRARY_USE_LIB64_PATHS false)
else()
include(CheckCCompilerFlag)
check_c_compiler_flag("-mfsrra" COMPILER_HAS_FSRRA)
check_c_compiler_flag("-mfsca" COMPILER_HAS_FSCA)
if(COMPILER_HAS_FSRRA)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfsrra")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfsrra")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -mfsrra")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -mfsrra")
endif()
if(COMPILER_HAS_FSCA)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfsca")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfsca")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -mfsca")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -mfsca")
endif()
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ffp-contract=fast -ffast-math")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffast-math")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ffp-contract=fast -ffast-math")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -ffast-math")
endif()
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -fexpensive-optimizations -fomit-frame-pointer -finline-functions")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++14 -O3 -g0 -s -fomit-frame-pointer -fstrict-aliasing")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3 -fexpensive-optimizations -fomit-frame-pointer -finline-functions")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -std=c++14 -O3 -fomit-frame-pointer -fstrict-aliasing")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -g -Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g -Wall -Wextra")
set(
SOURCES
containers/aligned_vector.c
containers/named_array.c
containers/stack.c
GL/clip.c
GL/draw.c
GL/error.c
GL/flush.c
@ -40,11 +77,10 @@ set(
GL/immediate.c
GL/lighting.c
GL/matrix.c
GL/profiler.c
GL/state.c
GL/texture.c
GL/util.c
GL/yalloc/yalloc.c
GL/alloc/alloc.c
${CMAKE_CURRENT_BINARY_DIR}/version.c
)
@ -59,7 +95,9 @@ configure_file(GL/version.c.in ${CMAKE_CURRENT_BINARY_DIR}/version.c)
if(PLATFORM_DREAMCAST)
set(SOURCES ${SOURCES} GL/platforms/sh4.c)
else()
find_package(SDL2 REQUIRED)
find_package(PkgConfig)
pkg_check_modules(SDL2 REQUIRED sdl2)
include_directories(${SDL2_INCLUDE_DIRS})
link_libraries(${SDL2_LIBRARIES})
set(
@ -72,6 +110,18 @@ else()
endif()
add_library(GLdc STATIC ${SOURCES})
if(FLTO_SUPPORTED)
set_property(TARGET GLdc PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
if(NOT PLATFORM_DREAMCAST)
set_target_properties(GLdc PROPERTIES
COMPILE_OPTIONS "-m32"
LINK_OPTIONS "-m32"
)
endif()
link_libraries(m)
include_directories(include)
@ -88,6 +138,13 @@ function(gen_sample sample)
add_executable(${sample} ${SAMPLE_SRCS})
if(FLTO_SUPPORTED)
# FIXME: Cubes + LTO causes an ICE
if(NOT ${sample} MATCHES "cubes")
set_property(TARGET ${sample} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
endif()
if(PLATFORM_DREAMCAST)
if(EXISTS "${CMAKE_SOURCE_DIR}/samples/${sample}/romdisk")
message("Generating romdisk for sample: ${sample}")
@ -110,17 +167,23 @@ function(gen_sample sample)
else()
message("No such romdisk for sample: ${sample} at 'samples/${sample}/romdisk'")
endif()
else()
set_target_properties(${sample} PROPERTIES
COMPILE_OPTIONS "-m32"
LINK_OPTIONS "-m32"
)
endif()
endfunction()
add_subdirectory(tests)
gen_sample(blend_test samples/blend_test/main.c)
gen_sample(depth_funcs samples/depth_funcs/main.c)
gen_sample(depth_funcs_alpha_testing samples/depth_funcs_alpha_testing/main.c samples/depth_funcs_alpha_testing/gl_png.c)
gen_sample(depth_funcs_ortho samples/depth_funcs_ortho/main.c)
gen_sample(lerabot01 samples/lerabot01/main.c)
gen_sample(lerabot_blend_test samples/lerabot_blend_test/main.c)
gen_sample(lights samples/lights/main.c)
gen_sample(mipmap samples/mipmap/main.c)
gen_sample(lerabot01 samples/lerabot01/main.c samples/loadbmp.c)
gen_sample(lights samples/lights/main.c samples/loadbmp.c)
gen_sample(mipmap samples/mipmap/main.c samples/loadbmp.c)
gen_sample(multitexture_arrays samples/multitexture_arrays/main.c samples/multitexture_arrays/pvr-texture.c)
gen_sample(nehe02 samples/nehe02/main.c)
gen_sample(nehe02de samples/nehe02de/main.c)
@ -128,9 +191,12 @@ gen_sample(nehe02va samples/nehe02va/main.c)
gen_sample(nehe03 samples/nehe03/main.c)
gen_sample(nehe04 samples/nehe04/main.c)
gen_sample(nehe05 samples/nehe05/main.c)
gen_sample(nehe06 samples/nehe06/main.c)
gen_sample(nehe06 samples/nehe06/main.c samples/loadbmp.c)
gen_sample(nehe06_vq samples/nehe06_vq/main.c)
gen_sample(nehe06_4444twid samples/nehe06_4444twid/main.c)
gen_sample(nehe08 samples/nehe08/main.c samples/nehe08/pvr-texture.c)
gen_sample(nehe10 samples/nehe10/main.c samples/loadbmp.c)
gen_sample(nehe20 samples/nehe20/main.c samples/loadbmp.c)
gen_sample(ortho2d samples/ortho2d/main.c)
gen_sample(paletted samples/paletted/main.c)
gen_sample(paletted_pcx samples/paletted_pcx/main.c)
@ -140,9 +206,15 @@ gen_sample(zclip samples/zclip/main.c)
gen_sample(zclip_triangle samples/zclip_triangle/main.c)
gen_sample(zclip_trianglestrip samples/zclip_trianglestrip/main.c)
gen_sample(scissor samples/scissor/main.c)
gen_sample(polymark samples/polymark/main.c)
gen_sample(cubes samples/cubes/main.cpp)
gen_sample(zclip_test tests/zclip/main.cpp)
if(PLATFORM_DREAMCAST)
gen_sample(polymark samples/polymark/main.c)
gen_sample(quadmark samples/quadmark/main.c)
gen_sample(trimark samples/trimark/main.c)
gen_sample(quadmark samples/quadmark/main.c samples/profiler.c)
gen_sample(prof_texture_upload samples/prof_texture_upload/main.c samples/profiler.c)
else()
gen_sample(quadmark samples/quadmark/main.c)
gen_sample(prof_texture_upload samples/prof_texture_upload/main.c)
endif()

534
GL/alloc/alloc.c Normal file
View File

@ -0,0 +1,534 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "alloc.h"
/* This allocator is designed so that ideally all allocations larger
* than 2k, fall on a 2k boundary. Smaller allocations will
* never cross a 2k boundary.
*
* House keeping is stored in RAM to avoid reading back from the
* VRAM to check for usage. Headers can't be easily stored in the
* blocks anyway as they have to be 2k aligned (so you'd need to
* store them in reverse or something)
*
* Defragmenting the pool will move larger allocations first, then
* smaller ones, recursively until you tell it to stop, or until things
* stop moving.
*
* The maximum pool size is 8M, made up of:
*
* - 4096 blocks of 2k
* - each with 8 sub-blocks of 256 bytes
*
* Why?
*
* The PVR performs better if textures don't cross 2K memory
* addresses, so we try to avoid that. Obviously we can't
* if the allocation is > 2k, but in that case we can at least
* align with 2k and the VQ codebook (which is usually 2k) will
* be in its own page.
*
* The smallest PVR texture allowed is 8x8 at 16 bit (so 128 bytes)
* but we're unlikely to use too many of those, so having a min sub-block
* size of 256 should be OK (a 16x16 image is 512, so two sub-blocks).
*
* We could go down to 128 bytes if wastage is an issue, but then we have
* to store double the number of usage markers.
*
* FIXME:
*
* - Only operates on one pool (ignores what you pass)
*/
#include <assert.h>
#include <stdio.h>
#define EIGHT_MEG (8 * 1024 * 1024)
#define TWO_KILOBYTES (2 * 1024)
#define BLOCK_COUNT (EIGHT_MEG / TWO_KILOBYTES)
#define ALLOC_DEBUG 0
#if ALLOC_DEBUG
#define DBG_MSG(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
#else
#define DBG_MSG(fmt, ...) do {} while (0)
#endif
static inline intptr_t round_up(intptr_t n, int multiple)
{
if((n % multiple) == 0) {
return n;
}
assert(multiple);
return ((n + multiple - 1) / multiple) * multiple;
}
struct AllocEntry {
void* pointer;
size_t size;
struct AllocEntry* next;
};
typedef struct {
/* This is a usage bitmask for each block. A block
* is divided into 8 x 256 byte subblocks. If a block
* is entirely used, it's value will be 255, if
* it's entirely free then it will be 0.
*/
uint8_t block_usage[BLOCK_COUNT];
uint8_t* pool; // Pointer to the memory pool
size_t pool_size; // Size of the memory pool
uint8_t* base_address; // First 2k aligned address in the pool
size_t block_count; // Number of 2k blocks in the pool
/* It's frustrating that we need to do this dynamically
* but we need to know the size allocated when we free()...
* we could store it statically but it would take 64k if we had
* an array of block_index -> block size where there would be 2 ** 32
* entries of 16 bit block sizes. The drawback (aside the memory usage)
* would be that we won't be able to order by size, so defragging will
* take much more time.*/
struct AllocEntry* allocations;
} PoolHeader;
static PoolHeader pool_header = {
{0}, NULL, 0, NULL, 0, NULL
};
void* alloc_base_address(void* pool) {
(void) pool;
return pool_header.base_address;
}
size_t alloc_block_count(void* pool) {
(void) pool;
return pool_header.block_count;
}
static inline void* calc_address(
uint8_t* block_usage_iterator,
int bit_offset,
size_t required_subblocks,
size_t* start_subblock_out
) {
uintptr_t offset = (block_usage_iterator - pool_header.block_usage) * 8;
offset += (bit_offset + 1);
offset -= required_subblocks;
if(start_subblock_out) {
*start_subblock_out = offset;
}
return pool_header.base_address + (offset * 256);
}
void* alloc_next_available_ex(void* pool, size_t required_size, size_t* start_subblock, size_t* required_subblocks);
void* alloc_next_available(void* pool, size_t required_size) {
return alloc_next_available_ex(pool, required_size, NULL, NULL);
}
void* alloc_next_available_ex(void* pool, size_t required_size, size_t* start_subblock_out, size_t* required_subblocks_out) {
(void) pool;
uint8_t* it = pool_header.block_usage;
uint32_t required_subblocks = (required_size / 256);
if(required_size % 256) required_subblocks += 1;
/* Anything gte to 2048 must be aligned to a 2048 boundary */
bool requires_alignment = required_size >= 2048;
if(required_subblocks_out) {
*required_subblocks_out = required_subblocks;
}
/* This is a fallback option. If while we're searching we find a possible slot
* but it's not aligned, or it's straddling a 2k boundary, then we store
* it here and if we reach the end of the search and find nothing better
* we use this instead */
uint8_t* poor_option = NULL;
size_t poor_start_subblock = 0;
uint32_t found_subblocks = 0;
uint32_t found_poor_subblocks = 0;
for(size_t j = 0; j < pool_header.block_count; ++j, ++it) {
/* We just need to find enough consecutive blocks */
if(found_subblocks < required_subblocks) {
uint8_t t = *it;
/* Optimisation only. Skip over full blocks */
if(t == 255) {
found_subblocks = 0;
found_poor_subblocks = 0;
} else {
/* Now let's see how many consecutive blocks we can find */
for(int i = 0; i < 8; ++i) {
if((t & 0x80) == 0) {
bool block_overflow = (
required_size < 2048 && found_subblocks > 0 && i == 0
);
bool reset_subblocks = (
(requires_alignment && found_subblocks == 0 && i != 0) ||
block_overflow
);
if(reset_subblocks) {
// Ignore this subblock, because we want the first subblock to be aligned
// at a 2048 boundary and this one isn't (i != 0)
found_subblocks = 0;
} else {
found_subblocks++;
}
/* If we reset the subblocks due to an overflow, we still
* want to count this free subblock in our count */
if(block_overflow) {
found_subblocks++;
}
found_poor_subblocks++;
if(found_subblocks >= required_subblocks) {
/* We found space! Now calculate the address */
return calc_address(it, i, required_subblocks, start_subblock_out);
}
if(!poor_option && (found_poor_subblocks >= required_subblocks)) {
poor_option = calc_address(it, i, required_subblocks, &poor_start_subblock);
}
} else {
found_subblocks = 0;
found_poor_subblocks = 0;
}
t <<= 1;
}
}
}
}
if(poor_option) {
if(start_subblock_out) {
*start_subblock_out = poor_start_subblock;
}
return poor_option;
} else {
return NULL;
}
}
int alloc_init(void* pool, size_t size) {
(void) pool;
if(pool_header.pool) {
return -1;
}
if(size > EIGHT_MEG) { // FIXME: >= ?
return -1;
}
uint8_t* p = (uint8_t*) pool;
memset(pool_header.block_usage, 0, BLOCK_COUNT);
pool_header.pool = pool;
pool_header.pool_size = size;
intptr_t base_address = (intptr_t) pool_header.pool;
base_address = round_up(base_address, 2048);
pool_header.base_address = (uint8_t*) base_address;
pool_header.block_count = ((p + size) - pool_header.base_address) / 2048;
pool_header.allocations = NULL;
assert(((uintptr_t) pool_header.base_address) % 2048 == 0);
return 0;
}
void alloc_shutdown(void* pool) {
(void) pool;
if(!pool_header.pool) {
return;
}
struct AllocEntry* it = pool_header.allocations;
while(it) {
struct AllocEntry* next = it->next;
free(it);
it = next;
}
memset(&pool_header, 0, sizeof(pool_header));
pool_header.pool = NULL;
}
static inline uint32_t size_to_subblock_count(size_t size) {
uint32_t required_subblocks = (size / 256);
if(size % 256) required_subblocks += 1;
return required_subblocks;
}
static inline uint32_t subblock_from_pointer(void* p) {
uint8_t* ptr = (uint8_t*) p;
return (ptr - pool_header.base_address) / 256;
}
static inline void block_and_offset_from_subblock(size_t sb, size_t* b, uint8_t* off) {
*b = sb / 8;
*off = (sb % 8);
}
void* alloc_malloc(void* pool, size_t size) {
DBG_MSG("Allocating: %d\n", size);
size_t start_subblock, required_subblocks;
void* ret = alloc_next_available_ex(pool, size, &start_subblock, &required_subblocks);
if(ret) {
size_t block;
uint8_t offset;
block_and_offset_from_subblock(start_subblock, &block, &offset);
uint8_t mask = 0;
DBG_MSG("Alloc: size: %d, rs: %d, sb: %d, b: %d, off: %d\n", size, required_subblocks, start_subblock, start_subblock / 8, start_subblock % 8);
/* Toggle any bits for the first block */
int c = (required_subblocks < 8) ? required_subblocks : 8;
for(int i = 0; i < c; ++i) {
mask |= (1 << (7 - (offset + i)));
required_subblocks--;
}
if(mask) {
pool_header.block_usage[block++] |= mask;
}
/* Fill any full blocks in the middle of the allocation */
while(required_subblocks > 8) {
pool_header.block_usage[block++] = 255;
required_subblocks -= 8;
}
/* Fill out any trailing subblocks */
mask = 0;
for(size_t i = 0; i < required_subblocks; ++i) {
mask |= (1 << (7 - i));
}
if(mask) {
pool_header.block_usage[block++] |= mask;
}
/* Insert allocations in the list by size descending so that when we
* defrag we can move the larger blocks before the smaller ones without
* much effort */
struct AllocEntry* new_entry = (struct AllocEntry*) malloc(sizeof(struct AllocEntry));
new_entry->pointer = ret;
new_entry->size = size;
new_entry->next = NULL;
struct AllocEntry* it = pool_header.allocations;
struct AllocEntry* last = NULL;
if(!it) {
pool_header.allocations = new_entry;
} else {
while(it) {
if(it->size < size) {
if(last) {
last->next = new_entry;
} else {
pool_header.allocations = new_entry;
}
new_entry->next = it;
break;
} else if(!it->next) {
it->next = new_entry;
new_entry->next = NULL;
break;
}
last = it;
it = it->next;
}
}
}
DBG_MSG("Alloc done\n");
return ret;
}
static void alloc_release_blocks(struct AllocEntry* it) {
size_t used_subblocks = size_to_subblock_count(it->size);
size_t subblock = subblock_from_pointer(it->pointer);
size_t block;
uint8_t offset;
block_and_offset_from_subblock(subblock, &block, &offset);
uint8_t mask = 0;
DBG_MSG("Free: size: %d, us: %d, sb: %d, off: %d\n", it->size, used_subblocks, block, offset);
/* Wipe out any leading subblocks */
int c = (used_subblocks < 8) ? used_subblocks : 8;
for(int i = 0; i < c; ++i) {
mask |= (1 << (7 - (offset + i)));
used_subblocks--;
}
if(mask) {
pool_header.block_usage[block++] &= ~mask;
}
/* Clear any full blocks in the middle of the allocation */
while(used_subblocks > 8) {
pool_header.block_usage[block++] = 0;
used_subblocks -= 8;
}
/* Wipe out any trailing subblocks */
mask = 0;
for(size_t i = 0; i < used_subblocks; ++i) {
mask |= (1 << (7 - i));
}
if(mask) {
pool_header.block_usage[block++] &= ~mask;
}
}
void alloc_free(void* pool, void* p) {
(void) pool;
struct AllocEntry* it = pool_header.allocations;
struct AllocEntry* last = NULL;
while(it) {
if(it->pointer == p) {
alloc_release_blocks(it);
if(last) {
last->next = it->next;
} else {
assert(it == pool_header.allocations);
pool_header.allocations = it->next;
}
DBG_MSG("Freed: size: %d, us: %d, sb: %d, off: %d\n", it->size, used_subblocks, block, offset);
free(it);
break;
}
last = it;
it = it->next;
}
DBG_MSG("Free done\n");
}
void alloc_run_defrag(void* pool, defrag_address_move callback, int max_iterations, void* user_data) {
for(int i = 0; i < max_iterations; ++i) {
bool move_occurred = false;
struct AllocEntry* it = pool_header.allocations;
if(!it) {
return;
}
while(it) {
void* potential_dest = alloc_next_available(pool, it->size);
if(potential_dest < it->pointer) {
potential_dest = alloc_malloc(pool, it->size);
memcpy(potential_dest, it->pointer, it->size);
/* Mark this block as now free, but don't fiddle with the
* allocation list */
alloc_release_blocks(it);
callback(it->pointer, potential_dest, user_data);
it->pointer = potential_dest;
move_occurred = true;
}
it = it->next;
}
if(!move_occurred) {
return;
}
}
}
static inline uint8_t count_ones(uint8_t byte) {
static const uint8_t NIBBLE_LOOKUP [16] = {
0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4
};
return NIBBLE_LOOKUP[byte & 0x0F] + NIBBLE_LOOKUP[byte >> 4];
}
size_t alloc_count_free(void* pool) {
(void) pool;
uint8_t* it = pool_header.block_usage;
uint8_t* end = it + pool_header.block_count;
size_t total_free = 0;
while(it < end) {
total_free += count_ones(*it) * 256;
++it;
}
return total_free;
}
size_t alloc_count_continuous(void* pool) {
(void) pool;
size_t largest_block = 0;
uint8_t* it = pool_header.block_usage;
uint8_t* end = it + pool_header.block_count;
size_t current_block = 0;
while(it < end) {
uint8_t t = *it++;
if(!t) {
current_block += 2048;
} else {
for(int i = 7; i >= 0; --i) {
bool bitset = (t & (1 << i));
if(bitset) {
current_block += (7 - i) * 256;
if(largest_block < current_block) {
largest_block = current_block;
current_block = 0;
}
}
}
}
}
return largest_block;
}

29
GL/alloc/alloc.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
int alloc_init(void* pool, size_t size);
void alloc_shutdown(void* pool);
void *alloc_malloc(void* pool, size_t size);
void alloc_free(void* pool, void* p);
typedef void (defrag_address_move)(void*, void*, void*);
void alloc_run_defrag(void* pool, defrag_address_move callback, int max_iterations, void* user_data);
size_t alloc_count_free(void* pool);
size_t alloc_count_continuous(void* pool);
void* alloc_next_available(void* pool, size_t required_size);
void* alloc_base_address(void* pool);
size_t alloc_block_count(void* pool);
#ifdef __cplusplus
}
#endif

406
GL/clip.c
View File

@ -1,406 +0,0 @@
#include <float.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#ifdef _arch_dreamcast
#include <dc/pvr.h>
#else
#define PVR_PACK_COLOR(a, r, g, b) {}
#endif
#include "profiler.h"
#include "private.h"
#include "../containers/aligned_vector.h"
static unsigned char ZCLIP_ENABLED = 1;
unsigned char _glIsClippingEnabled() {
return ZCLIP_ENABLED;
}
void _glEnableClipping(unsigned char v) {
ZCLIP_ENABLED = v;
}
inline float _glClipLineToNearZ(const Vertex* v1, const Vertex* v2, Vertex* vout) {
const float d0 = v1->w + v1->xyz[2];
const float d1 = v2->w + v2->xyz[2];
/* We need to shift 't' a little, to avoid the possibility that a
* rounding error leaves the new vertex behind the near plane. We shift
* according to the direction we're clipping across the plane */
const float epsilon = (d0 < d1) ? -0.000001 : 0.000001;
float t = MATH_Fast_Divide(d0, (d0 - d1)) + epsilon;
vout->xyz[0] = MATH_fmac(v2->xyz[0] - v1->xyz[0], t, v1->xyz[0]);
vout->xyz[1] = MATH_fmac(v2->xyz[1] - v1->xyz[1], t, v1->xyz[1]);
vout->xyz[2] = MATH_fmac(v2->xyz[2] - v1->xyz[2], t, v1->xyz[2]);
/*
printf(
"(%f, %f, %f, %f) -> %f -> (%f, %f, %f, %f) = (%f, %f, %f)\n",
v1->xyz[0], v1->xyz[1], v1->xyz[2], v1->w, t,
v2->xyz[0], v2->xyz[1], v2->xyz[2], v2->w,
vout->xyz[0], vout->xyz[1], vout->xyz[2]
);*/
return t;
}
GL_FORCE_INLINE void interpolateFloat(const float v1, const float v2, const float t, float* out) {
*out = MATH_fmac(v2 - v1,t, v1);
}
GL_FORCE_INLINE void interpolateVec2(const float* v1, const float* v2, const float t, float* out) {
interpolateFloat(v1[0], v2[0], t, &out[0]);
interpolateFloat(v1[1], v2[1], t, &out[1]);
}
GL_FORCE_INLINE void interpolateVec3(const float* v1, const float* v2, const float t, float* out) {
interpolateFloat(v1[0], v2[0], t, &out[0]);
interpolateFloat(v1[1], v2[1], t, &out[1]);
interpolateFloat(v1[2], v2[2], t, &out[2]);
}
GL_FORCE_INLINE void interpolateVec4(const float* v1, const float* v2, const float t, float* out) {
interpolateFloat(v1[0], v2[0], t, &out[0]);
interpolateFloat(v1[1], v2[1], t, &out[1]);
interpolateFloat(v1[2], v2[2], t, &out[2]);
interpolateFloat(v1[3], v2[3], t, &out[3]);
}
GL_FORCE_INLINE void interpolateColour(const uint8_t* v1, const uint8_t* v2, const float t, uint8_t* out) {
out[0] = v1[0] + (uint32_t) (((float) (v2[0] - v1[0])) * t);
out[1] = v1[1] + (uint32_t) (((float) (v2[1] - v1[1])) * t);
out[2] = v1[2] + (uint32_t) (((float) (v2[2] - v1[2])) * t);
out[3] = v1[3] + (uint32_t) (((float) (v2[3] - v1[3])) * t);
}
const uint32_t VERTEX_CMD_EOL = 0xf0000000;
const uint32_t VERTEX_CMD = 0xe0000000;
typedef struct {
Vertex vertex[3];
VertexExtra extra[3];
uint8_t visible;
} Triangle;
void _glClipTriangle(const Triangle* triangle, const uint8_t visible, SubmissionTarget* target, const uint8_t flatShade) {
Vertex* last = NULL;
VertexExtra* veLast = NULL;
const Vertex* vertices = triangle->vertex;
const VertexExtra* extras = triangle->extra;
char* bgra = (char*) vertices[2].bgra;
/* Used when flat shading is enabled */
uint32_t finalColour = *((uint32_t*) bgra);
Vertex tmp;
VertexExtra veTmp;
uint8_t pushedCount = 0;
#define IS_VISIBLE(x) (visible & (1 << (2 - (x)))) > 0
#define PUSH_VERT(vert, ve) \
last = aligned_vector_push_back(&target->output->vector, vert, 1); \
last->flags = VERTEX_CMD; \
veLast = aligned_vector_push_back(target->extras, ve, 1); \
++pushedCount;
#define CLIP_TO_PLANE(vert1, ve1, vert2, ve2) \
do { \
float t = _glClipLineToNearZ((vert1), (vert2), &tmp); \
interpolateFloat((vert1)->w, (vert2)->w, t, &tmp.w); \
interpolateVec2((vert1)->uv, (vert2)->uv, t, tmp.uv); \
interpolateVec3((ve1)->nxyz, (ve2)->nxyz, t, veTmp.nxyz); \
interpolateVec2((ve1)->st, (ve2)->st, t, veTmp.st); \
if(flatShade) { \
interpolateColour((const uint8_t*) &finalColour, (const uint8_t*) &finalColour, t, tmp.bgra); \
} else { interpolateColour((vert1)->bgra, (vert2)->bgra, t, tmp.bgra); } \
} while(0); \
uint8_t v0 = IS_VISIBLE(0);
uint8_t v1 = IS_VISIBLE(1);
uint8_t v2 = IS_VISIBLE(2);
if(v0) {
PUSH_VERT(&vertices[0], &extras[0]);
}
if(v0 != v1) {
CLIP_TO_PLANE(&vertices[0], &extras[0], &vertices[1], &extras[1]);
PUSH_VERT(&tmp, &veTmp);
}
if(v1) {
PUSH_VERT(&vertices[1], &extras[1]);
}
if(v1 != v2) {
CLIP_TO_PLANE(&vertices[1], &extras[1], &vertices[2], &extras[2]);
PUSH_VERT(&tmp, &veTmp);
}
if(v2) {
PUSH_VERT(&vertices[2], &extras[2]);
}
if(v2 != v0) {
CLIP_TO_PLANE(&vertices[2], &extras[2], &vertices[0], &extras[0]);
PUSH_VERT(&tmp, &veTmp);
}
if(pushedCount == 4) {
Vertex* prev = last - 1;
VertexExtra* prevVe = veLast - 1;
tmp = *prev;
veTmp = *prevVe;
*prev = *last;
*prevVe = *veLast;
*last = tmp;
*veLast = veTmp;
prev->flags = VERTEX_CMD;
last->flags = VERTEX_CMD_EOL;
} else {
/* Set the last flag to the end of the new strip */
last->flags = VERTEX_CMD_EOL;
}
}
static inline void markDead(Vertex* vert) {
vert->flags = VERTEX_CMD_EOL;
// If we're debugging, wipe out the xyz
#ifndef NDEBUG
typedef union {
float* f;
int* i;
} cast;
cast v1, v2, v3;
v1.f = &vert->xyz[0];
v2.f = &vert->xyz[1];
v3.f = &vert->xyz[2];
*v1.i = 0xDEADBEEF;
*v2.i = 0xDEADBEEF;
*v3.i = 0xDEADBEEF;
#endif
}
#define B000 0
#define B111 7
#define B100 4
#define B010 2
#define B001 1
#define B101 5
#define B011 3
#define B110 6
#define MAX_CLIP_TRIANGLES 255
void _glClipTriangleStrip(SubmissionTarget* target, uint8_t fladeShade) {
static Triangle TO_CLIP[MAX_CLIP_TRIANGLES];
static uint8_t CLIP_COUNT = 0;
CLIP_COUNT = 0;
Vertex* vertex = _glSubmissionTargetStart(target);
const Vertex* end = _glSubmissionTargetEnd(target);
const Vertex* start = vertex;
int32_t triangle = -1;
/* Go to the (potential) end of the first triangle */
vertex++;
uint32_t vi1, vi2, vi3;
while(vertex < end) {
vertex++;
triangle++;
uint8_t even = (triangle % 2) == 0;
Vertex* v1 = (even) ? vertex - 2 : vertex - 1;
Vertex* v2 = (even) ? vertex - 1 : vertex - 2;
Vertex* v3 = vertex;
/* Skip ahead if we don't have a complete triangle yet */
if(v1->flags != VERTEX_CMD || v2->flags != VERTEX_CMD) {
triangle = -1;
continue;
}
/* Indexes into extras array */
vi1 = v1 - start;
vi2 = v2 - start;
vi3 = v3 - start;
/*
* A vertex is visible if it's in front of the camera (W > 0)
* and it's in front of the near plane (Z > -W)
*/
#define _VERT_VISIBLE(v) \
(v->w >= 0 && v->xyz[2] >= -v->w) \
uint8_t visible = (
(_VERT_VISIBLE(v1) ? 4 : 0) |
(_VERT_VISIBLE(v2) ? 2 : 0) |
(_VERT_VISIBLE(v3) ? 1 : 0)
);
switch(visible) {
case B111:
/* All visible? Do nothing */
continue;
break;
case B000:
/*
It is not possible that this is any trangle except the first
in a strip. That's because:
- It's either the first triangle submitted
- A previous triangle must have been clipped and the strip
restarted behind the plane
So, we effectively reboot the strip. We mark the first vertex
as the end (so it's ignored) then mark the next two as the
start of a new strip. Then if the next triangle crosses
back into view, we clip correctly. This will potentially
result in a bunch of pointlessly submitted vertices.
FIXME: Skip submitting those verts
*/
/* Even though this is always the first in the strip, it can also
* be the last */
if(v3->flags == VERTEX_CMD_EOL) {
/* Wipe out the triangle */
markDead(v1);
markDead(v2);
markDead(v3);
} else {
markDead(v1);
swapVertex(v2, v3);
triangle = -1;
v2->flags = VERTEX_CMD;
v3->flags = VERTEX_CMD;
}
break;
case B100:
case B010:
case B001:
case B101:
case B011:
case B110:
assert(CLIP_COUNT < MAX_CLIP_TRIANGLES);
/* Store the triangle for clipping */
TO_CLIP[CLIP_COUNT].vertex[0] = *v1;
TO_CLIP[CLIP_COUNT].vertex[1] = *v2;
TO_CLIP[CLIP_COUNT].vertex[2] = *v3;
VertexExtra* ve1 = (VertexExtra*) aligned_vector_at(target->extras, vi1);
VertexExtra* ve2 = (VertexExtra*) aligned_vector_at(target->extras, vi2);
VertexExtra* ve3 = (VertexExtra*) aligned_vector_at(target->extras, vi3);
TO_CLIP[CLIP_COUNT].extra[0] = *ve1;
TO_CLIP[CLIP_COUNT].extra[1] = *ve2;
TO_CLIP[CLIP_COUNT].extra[2] = *ve3;
TO_CLIP[CLIP_COUNT].visible = visible;
++CLIP_COUNT;
/*
OK so here's the clever bit. If any triangle except
the first or last needs clipping, then the next one does aswell
(you can't draw a plane through a single triangle in the middle of a
strip, only 2+). This means we can clip in pairs which frees up two
vertices in the middle of the strip, which is exactly the space
we need to restart the triangle strip after the next triangle
*/
if(v3->flags == VERTEX_CMD_EOL) {
/* Last triangle in strip so end a vertex early */
if(triangle == 0) {
// Wipe out the triangle completely
markDead(v1);
markDead(v2);
} else {
// End the strip
(vertex - 1)->flags = VERTEX_CMD_EOL;
}
markDead(vertex);
triangle = -1;
} else if(triangle == 0) {
/* First triangle in strip, remove first vertex */
markDead(v1);
v2->flags = VERTEX_CMD;
v3->flags = VERTEX_CMD;
triangle = -1;
} else {
Vertex* v4 = v3 + 1;
uint32_t vi4 = v4 - start;
TO_CLIP[CLIP_COUNT].vertex[0] = *v3;
TO_CLIP[CLIP_COUNT].vertex[1] = *v2;
TO_CLIP[CLIP_COUNT].vertex[2] = *v4;
VertexExtra* ve4 = (VertexExtra*) aligned_vector_at(target->extras, vi4);
TO_CLIP[CLIP_COUNT].extra[0] = *(VertexExtra*) aligned_vector_at(target->extras, vi3);
TO_CLIP[CLIP_COUNT].extra[1] = *(VertexExtra*) aligned_vector_at(target->extras, vi2);
TO_CLIP[CLIP_COUNT].extra[2] = *ve4;
visible = (_VERT_VISIBLE(v3) ? 4 : 0) |
(_VERT_VISIBLE(v2) ? 2 : 0) |
(_VERT_VISIBLE(v4) ? 1 : 0);
TO_CLIP[CLIP_COUNT].visible = visible;
++CLIP_COUNT;
// Restart strip
triangle = -1;
// Mark the second vertex as the end of the strip
(vertex - 1)->flags = VERTEX_CMD_EOL;
if(v4->flags == VERTEX_CMD_EOL) {
markDead(v3);
markDead(v4);
} else {
// Swap the next vertices to start a new strip
swapVertex(v3, v4);
v3->flags = VERTEX_CMD;
v4->flags = VERTEX_CMD;
/* Swap the extra data too */
VertexExtra t = *ve4;
*ve3 = *ve4;
*ve4 = t;
}
}
break;
default:
break;
}
}
/* Now, clip all the triangles and append them to the output */
GLushort i;
for(i = 0; i < CLIP_COUNT; ++i) {
_glClipTriangle(&TO_CLIP[i], TO_CLIP[i].visible, target, fladeShade);
}
}

1157
GL/draw.c

File diff suppressed because it is too large Load Diff

127
GL/draw_fastpath.inc Normal file
View File

@ -0,0 +1,127 @@
/* THIS FILE IS INCLUDED BY draw.c TO AVOID CODE DUPLICATION. IT'S AN UGLY HACK */
#define FUNC_NAME(mode) static void generateArraysFastPath##_##mode(SubmissionTarget* target, const GLsizei first, const GLuint count)
#define MAKE_FUNC(mode) FUNC_NAME(mode)
MAKE_FUNC(POLYMODE)
{
static const float w = 1.0f;
if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) {
/* If we don't have vertices, do nothing */
return;
}
/* This is the best value we have. PROCESS_VERTEX_FLAGS needs to operate on quads and tris and so
this need to be divisible by 4 and 3. Even though we should be able to go much higher than this
and still be cache-local, trial and error says otherwise... */
#define BATCH_SIZE 60
GLuint min = 0;
GLuint stride;
const GLubyte* ptr;
Vertex* it;
VertexExtra* ve;
for(min = 0; min < count; min += BATCH_SIZE) {
const Vertex* start = ((Vertex*) _glSubmissionTargetStart(target)) + min;
const int_fast32_t loop = ((min + BATCH_SIZE) > count) ? count - min : BATCH_SIZE;
const int offset = (first + min);
stride = ATTRIB_POINTERS.uv.stride;
ptr = (ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) ? ATTRIB_POINTERS.uv.ptr + ((first + min) * stride) : NULL;
it = (Vertex*) start;
if(ptr) {
PREFETCH(ptr);
for(int_fast32_t i = 0; i < loop; ++i, ++it) {
PREFETCH(ptr + stride);
it->uv[0] = ((float*) ptr)[0];
it->uv[1] = ((float*) ptr)[1];
ptr += stride;
}
} else {
for(int_fast32_t i = 0; i < loop; ++i, ++it) {
it->uv[0] = 0;
it->uv[1] = 0;
}
}
stride = ATTRIB_POINTERS.colour.stride;
ptr = (ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) ? ATTRIB_POINTERS.colour.ptr + (offset * stride) : NULL;
it = (Vertex*) start;
if(ptr) {
PREFETCH(ptr);
for(int_fast32_t i = 0; i < loop; ++i, ++it) {
PREFETCH(ptr + stride);
it->bgra[0] = ptr[0];
it->bgra[1] = ptr[1];
it->bgra[2] = ptr[2];
it->bgra[3] = ptr[3];
ptr += stride;
}
} else {
for(int_fast32_t i = 0; i < loop; ++i, ++it) {
*((uint32_t*) it->bgra) = ~0;
}
}
stride = ATTRIB_POINTERS.vertex.stride;
ptr = ATTRIB_POINTERS.vertex.ptr + (offset * stride);
it = (Vertex*) start;
PREFETCH(ptr);
for(int_fast32_t i = 0; i < loop; ++i, ++it) {
PREFETCH(ptr + stride);
TransformVertex((const float*) ptr, &w, it->xyz, &it->w);
PROCESS_VERTEX_FLAGS(it, min + i);
ptr += stride;
}
start = aligned_vector_at(target->extras, min);
stride = ATTRIB_POINTERS.st.stride;
ptr = (ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) ? ATTRIB_POINTERS.st.ptr + (offset * stride) : NULL;
ve = (VertexExtra*) start;
if(ptr) {
PREFETCH(ptr);
for(int_fast32_t i = 0; i < loop; ++i, ++ve) {
PREFETCH(ptr + stride);
ve->st[0] = ((float*) ptr)[0];
ve->st[1] = ((float*) ptr)[1];
ptr += stride;
}
} else {
for(int_fast32_t i = 0; i < loop; ++i, ++ve) {
ve->st[0] = 0;
ve->st[1] = 0;
}
}
stride = ATTRIB_POINTERS.normal.stride;
ptr = (ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG) ? ATTRIB_POINTERS.normal.ptr + (offset * stride) : NULL;
ve = (VertexExtra*) start;
if(ptr) {
PREFETCH(ptr);
for(int_fast32_t i = 0; i < loop; ++i, ++ve) {
PREFETCH(ptr + stride);
ve->nxyz[0] = ((float*) ptr)[0];
ve->nxyz[1] = ((float*) ptr)[1];
ve->nxyz[2] = ((float*) ptr)[2];
ptr += stride;
}
} else {
for(int_fast32_t i = 0; i < loop; ++i, ++ve) {
ve->nxyz[0] = 0;
ve->nxyz[1] = 0;
ve->nxyz[2] = 0;
}
}
}
}

View File

@ -12,8 +12,8 @@
#include "private.h"
static GLenum last_error = GL_NO_ERROR;
static char error_function[64] = { '\0' };
GLenum LAST_ERROR = GL_NO_ERROR;
char ERROR_FUNCTION[64] = { '\0' };
/* Quoth the GL Spec:
When an error occurs, the error flag is set to the appropriate error code
@ -24,44 +24,9 @@ static char error_function[64] = { '\0' };
Nothing in the spec requires recording multiple error flags, although it is
allowed by the spec. We take the easy way out for now. */
void _glKosThrowError(GLenum error, const char *function) {
if(last_error == GL_NO_ERROR) {
last_error = error;
sprintf(error_function, "%s\n", function);
}
}
GLubyte _glKosHasError() {
return (last_error != GL_NO_ERROR) ? GL_TRUE : GL_FALSE;
}
static void _glKosResetError() {
last_error = GL_NO_ERROR;
sprintf(error_function, "\n");
}
static const char* _glErrorEnumAsString(GLenum error) {
switch(error) {
case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
default:
return "GL_UNKNOWN_ERROR";
}
}
void _glKosPrintError() {
if(!_glKosHasError()) {
return;
}
fprintf(stderr, "GL ERROR: %s when calling %s\n", _glErrorEnumAsString(last_error), error_function);
_glKosResetError();
}
GLenum glGetError(void) {
GLenum rv = last_error;
GLenum rv = LAST_ERROR;
_glKosResetError();
return rv;
}

View File

@ -1,22 +1,21 @@
#include "../containers/aligned_vector.h"
#include "private.h"
#include "profiler.h"
static PolyList OP_LIST;
static PolyList PT_LIST;
static PolyList TR_LIST;
PolyList OP_LIST;
PolyList PT_LIST;
PolyList TR_LIST;
/**
* FAST_MODE will use invW for all Z coordinates sent to the
* GPU.
*
* This will break orthographic mode so default is FALSE
**/
PolyList* _glActivePolyList() {
if(_glIsBlendingEnabled()) {
return &TR_LIST;
} else if(_glIsAlphaTestEnabled()) {
return &PT_LIST;
} else {
return &OP_LIST;
}
}
#define FAST_MODE GL_FALSE
GLboolean AUTOSORT_ENABLED = GL_FALSE;
PolyList* _glOpaquePolyList() {
return &OP_LIST;
@ -43,20 +42,35 @@ void APIENTRY glKosInitConfig(GLdcConfig* config) {
config->autosort_enabled = GL_FALSE;
config->fsaa_enabled = GL_FALSE;
config->initial_op_capacity = 1024;
config->initial_pt_capacity = 512;
config->initial_tr_capacity = 1024;
config->initial_immediate_capacity = 1024;
config->initial_op_capacity = 1024 * 3;
config->initial_pt_capacity = 512 * 3;
config->initial_tr_capacity = 1024 * 3;
config->initial_immediate_capacity = 1024 * 3;
// RGBA4444 is the fastest general format - 8888 will cause a perf issue
config->internal_palette_format = GL_RGBA4;
config->texture_twiddle = GL_TRUE;
}
static bool _initialized = false;
void APIENTRY glKosInitEx(GLdcConfig* config) {
if(_initialized) {
return;
}
_initialized = true;
TRACE();
printf("\nWelcome to GLdc! Git revision: %s\n\n", GLDC_VERSION);
InitGPU(config->autosort_enabled, config->fsaa_enabled);
AUTOSORT_ENABLED = config->autosort_enabled;
_glInitSubmissionTarget();
_glInitMatrices();
_glInitAttributePointers();
_glInitContext();
@ -68,6 +82,10 @@ void APIENTRY glKosInitEx(GLdcConfig* config) {
_glInitTextures();
if(config->texture_twiddle) {
glEnable(GL_TEXTURE_TWIDDLE_KOS);
}
OP_LIST.list_type = GPU_LIST_OP_POLY;
PT_LIST.list_type = GPU_LIST_PT_POLY;
TR_LIST.list_type = GPU_LIST_TR_POLY;
@ -81,32 +99,39 @@ void APIENTRY glKosInitEx(GLdcConfig* config) {
aligned_vector_reserve(&TR_LIST.vector, config->initial_tr_capacity);
}
void APIENTRY glKosShutdown() {
aligned_vector_clear(&OP_LIST.vector);
aligned_vector_clear(&PT_LIST.vector);
aligned_vector_clear(&TR_LIST.vector);
}
void APIENTRY glKosInit() {
GLdcConfig config;
glKosInitConfig(&config);
glKosInitEx(&config);
}
void APIENTRY glKosSwapBuffers() {
static int frame_count = 0;
TRACE();
profiler_push(__func__);
SceneBegin();
SceneListBegin(GPU_LIST_OP_POLY);
SceneListSubmit(OP_LIST.vector.data, OP_LIST.vector.size);
SceneListFinish();
if(aligned_vector_header(&OP_LIST.vector)->size > 2) {
SceneListBegin(GPU_LIST_OP_POLY);
SceneListSubmit((Vertex*) aligned_vector_front(&OP_LIST.vector), aligned_vector_size(&OP_LIST.vector));
SceneListFinish();
}
SceneListBegin(GPU_LIST_PT_POLY);
SceneListSubmit(PT_LIST.vector.data, PT_LIST.vector.size);
SceneListFinish();
if(aligned_vector_header(&PT_LIST.vector)->size > 2) {
SceneListBegin(GPU_LIST_PT_POLY);
SceneListSubmit((Vertex*) aligned_vector_front(&PT_LIST.vector), aligned_vector_size(&PT_LIST.vector));
SceneListFinish();
}
SceneListBegin(GPU_LIST_TR_POLY);
SceneListSubmit(TR_LIST.vector.data, TR_LIST.vector.size);
SceneListFinish();
if(aligned_vector_header(&TR_LIST.vector)->size > 2) {
SceneListBegin(GPU_LIST_TR_POLY);
SceneListSubmit((Vertex*) aligned_vector_front(&TR_LIST.vector), aligned_vector_size(&TR_LIST.vector));
SceneListFinish();
}
SceneFinish();
aligned_vector_clear(&OP_LIST.vector);
@ -114,12 +139,4 @@ void APIENTRY glKosSwapBuffers() {
aligned_vector_clear(&TR_LIST.vector);
_glApplyScissor(true);
profiler_checkpoint("scene");
profiler_pop();
if(frame_count++ > 100) {
profiler_print_stats();
frame_count = 0;
}
}

View File

@ -40,7 +40,6 @@ void APIENTRY glFogf(GLenum pname, GLfloat param) {
case GL_FOG_INDEX:
default: {
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
}
}
}

View File

@ -1,5 +1,4 @@
#include <stdio.h>
#include <assert.h>
#include "private.h"
@ -81,13 +80,11 @@ void APIENTRY glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum
_GL_UNUSED(level);
if(texture != 0 && !glIsTexture(texture)) {
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
if(!ACTIVE_FRAMEBUFFER) {
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
@ -199,7 +196,7 @@ static GL_NO_INSTRUMENT GLboolean _glCalculateAverageTexel(GLuint pvrFormat, con
*d1 = PACK_ARGB4444(a, r, g, b);
} else {
assert(format == ARGB1555);
gl_assert(format == ARGB1555);
GLushort* s1 = (GLushort*) src1;
GLushort* s2 = (GLushort*) src2;
@ -248,8 +245,8 @@ GLboolean _glGenerateMipmapTwiddled(const GLuint pvrFormat, const GLubyte* prevD
const GLubyte* s4 = s3 + stride;
GLubyte* t = &thisData[j * stride];
assert(s4 < prevData + (lastHeight * lastWidth * stride));
assert(t < thisData + (thisHeight * thisWidth * stride));
gl_assert(s4 < prevData + (lastHeight * lastWidth * stride));
gl_assert(t < thisData + (thisHeight * thisWidth * stride));
_glCalculateAverageTexel(pvrFormat, s1, s2, s3, s4, t);
}
@ -257,10 +254,9 @@ GLboolean _glGenerateMipmapTwiddled(const GLuint pvrFormat, const GLubyte* prevD
return GL_TRUE;
}
void APIENTRY glGenerateMipmapEXT(GLenum target) {
void APIENTRY glGenerateMipmap(GLenum target) {
if(target != GL_TEXTURE_2D) {
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
@ -268,14 +264,18 @@ void APIENTRY glGenerateMipmapEXT(GLenum target) {
if(!tex || !tex->data || !tex->mipmapCount) {
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
if(tex->width != tex->height) {
fprintf(stderr, "[GL ERROR] Mipmaps cannot be supported on non-square textures\n");
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
if((tex->color & GPU_TXRFMT_PAL4BPP) == GPU_TXRFMT_PAL4BPP) {
fprintf(stderr, "[GL ERROR] Mipmap generation not supported for 4BPP paletted textures\n");
_glKosThrowError(GL_INVALID_OPERATION, __func__);
return;
}
@ -285,7 +285,6 @@ void APIENTRY glGenerateMipmapEXT(GLenum target) {
fprintf(stderr, "[GL ERROR] Mipmaps are only supported on twiddled textures\n");
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
@ -293,7 +292,6 @@ void APIENTRY glGenerateMipmapEXT(GLenum target) {
if(!complete && tex->isCompressed) {
fprintf(stderr, "[GL ERROR] Generating mipmaps for compressed textures is not yet supported\n");
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
@ -324,13 +322,24 @@ void APIENTRY glGenerateMipmapEXT(GLenum target) {
prevHeight = thisHeight;
}
assert(_glIsMipmapComplete(tex));
gl_assert(_glIsMipmapComplete(tex));
}
/* generate mipmaps for any image provided by the user and then pass them to OpenGL */
GLAPI GLvoid APIENTRY gluBuild2DMipmaps(GLenum target, GLint internalFormat,
GLsizei width, GLsizei height,
GLenum format, GLenum type, const void *data){
/* 2d texture, level of detail 0 (normal), 3 components (red, green, blue),
width & height of the image, border 0 (normal), rgb color data,
unsigned byte data, and finally the data itself. */
glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
GLenum APIENTRY glCheckFramebufferStatusEXT(GLenum target) {
if(target != GL_FRAMEBUFFER_EXT) {
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
return 0;
}

20
GL/gl_assert.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef NDEBUG
/* We're debugging, use normal assert */
#include <assert.h>
#define gl_assert assert
#else
/* Release mode, use our custom assert */
#include <stdio.h>
#include <stdlib.h>
#define gl_assert(x) \
do {\
if(!(x)) {\
fprintf(stderr, "Assertion failed at %s:%d\n", __FILE__, __LINE__);\
exit(1);\
}\
} while(0); \
#endif

View File

@ -10,77 +10,75 @@
#include <string.h>
#include <stdio.h>
#include "profiler.h"
#include "private.h"
static GLboolean IMMEDIATE_MODE_ACTIVE = GL_FALSE;
extern inline GLuint _glRecalcFastPath();
GLboolean IMMEDIATE_MODE_ACTIVE = GL_FALSE;
static GLenum ACTIVE_POLYGON_MODE = GL_TRIANGLES;
static GLfloat __attribute__((aligned(32))) NORMAL[3] = {0.0f, 0.0f, 1.0f};
static GLubyte __attribute__((aligned(32))) COLOR[4] = {255, 255, 255, 255}; /* ARGB order for speed */
static GLfloat __attribute__((aligned(32))) UV_COORD[2] = {0.0f, 0.0f};
static GLfloat __attribute__((aligned(32))) ST_COORD[2] = {0.0f, 0.0f};
static AlignedVector VERTICES;
static AlignedVector ST_COORDS;
static AlignedVector NORMALS;
static AttribPointerList IM_ATTRIBS;
static GLfloat NORMAL[3] = {0.0f, 0.0f, 1.0f};
static GLubyte COLOR[4] = {255, 255, 255, 255};
static GLfloat UV_COORD[2] = {0.0f, 0.0f};
static GLfloat ST_COORD[2] = {0.0f, 0.0f};
/* We store the list of attributes that have been "enabled" by a call to
glColor, glNormal, glTexCoord etc. otherwise we already have defaults that
can be applied faster */
static GLuint IM_ENABLED_VERTEX_ATTRIBUTES = 0;
typedef struct __attribute__((aligned(32))) {
GLfloat x;
GLfloat y;
GLfloat z;
GLfloat u;
GLfloat v;
GLfloat s;
GLfloat t;
GLubyte bgra[4];
GLfloat nx;
GLfloat ny;
GLfloat nz;
GLuint padding[5];
} IMVertex;
static AttribPointer VERTEX_ATTRIB;
static AttribPointer DIFFUSE_ATTRIB;
static AttribPointer UV_ATTRIB;
static AttribPointer ST_ATTRIB;
static AttribPointer NORMAL_ATTRIB;
void _glInitImmediateMode(GLuint initial_size) {
aligned_vector_init(&VERTICES, sizeof(GLVertexKOS));
aligned_vector_init(&ST_COORDS, sizeof(GLfloat));
aligned_vector_init(&NORMALS, sizeof(GLuint));
aligned_vector_init(&VERTICES, sizeof(IMVertex));
aligned_vector_reserve(&VERTICES, initial_size);
aligned_vector_reserve(&ST_COORDS, initial_size * 2);
aligned_vector_reserve(&NORMALS, initial_size);
VERTEX_ATTRIB.ptr = VERTICES.data + sizeof(uint32_t);
VERTEX_ATTRIB.size = 3;
VERTEX_ATTRIB.type = GL_FLOAT;
VERTEX_ATTRIB.stride = 32;
IM_ATTRIBS.vertex.ptr = aligned_vector_front(&VERTICES);
IM_ATTRIBS.vertex.size = 3;
IM_ATTRIBS.vertex.type = GL_FLOAT;
IM_ATTRIBS.vertex.stride = sizeof(IMVertex);
UV_ATTRIB.ptr = VERTEX_ATTRIB.ptr + (sizeof(GLfloat) * 3);
UV_ATTRIB.stride = 32;
UV_ATTRIB.type = GL_FLOAT;
UV_ATTRIB.size = 2;
IM_ATTRIBS.uv.ptr = IM_ATTRIBS.vertex.ptr + (sizeof(GLfloat) * 3);
IM_ATTRIBS.uv.stride = sizeof(IMVertex);
IM_ATTRIBS.uv.type = GL_FLOAT;
IM_ATTRIBS.uv.size = 2;
DIFFUSE_ATTRIB.ptr = VERTEX_ATTRIB.ptr + (sizeof(GLfloat) * 5);
DIFFUSE_ATTRIB.size = GL_BGRA; /* Flipped color order */
DIFFUSE_ATTRIB.type = GL_UNSIGNED_BYTE;
DIFFUSE_ATTRIB.stride = 32;
IM_ATTRIBS.st.ptr = IM_ATTRIBS.vertex.ptr + (sizeof(GLfloat) * 5);
IM_ATTRIBS.st.stride = sizeof(IMVertex);
IM_ATTRIBS.st.type = GL_FLOAT;
IM_ATTRIBS.st.size = 2;
NORMAL_ATTRIB.ptr = NORMALS.data;
NORMAL_ATTRIB.stride = 0;
NORMAL_ATTRIB.type = GL_UNSIGNED_INT_2_10_10_10_REV;
NORMAL_ATTRIB.size = 1;
IM_ATTRIBS.colour.ptr = IM_ATTRIBS.vertex.ptr + (sizeof(GLfloat) * 7);
IM_ATTRIBS.colour.size = GL_BGRA; /* Flipped color order */
IM_ATTRIBS.colour.type = GL_UNSIGNED_BYTE;
IM_ATTRIBS.colour.stride = sizeof(IMVertex);
ST_ATTRIB.ptr = ST_COORDS.data;
ST_ATTRIB.stride = 0;
ST_ATTRIB.type = GL_FLOAT;
ST_ATTRIB.size = 2;
}
GLubyte _glCheckImmediateModeInactive(const char* func) {
/* Returns 1 on error */
if(IMMEDIATE_MODE_ACTIVE) {
_glKosThrowError(GL_INVALID_OPERATION, func);
_glKosPrintError();
return 1;
}
return 0;
IM_ATTRIBS.normal.ptr = IM_ATTRIBS.vertex.ptr + (sizeof(GLfloat) * 7) + sizeof(uint32_t);
IM_ATTRIBS.normal.stride = sizeof(IMVertex);
IM_ATTRIBS.normal.type = GL_FLOAT;
IM_ATTRIBS.normal.size = 3;
}
void APIENTRY glBegin(GLenum mode) {
if(IMMEDIATE_MODE_ACTIVE) {
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
@ -89,90 +87,101 @@ void APIENTRY glBegin(GLenum mode) {
}
void APIENTRY glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
COLOR[0] = (GLubyte)(r * 255);
COLOR[1] = (GLubyte)(g * 255);
COLOR[2] = (GLubyte)(b * 255);
COLOR[3] = (GLubyte)(a * 255);
IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG;
COLOR[A8IDX] = (GLubyte)(a * 255.0f);
COLOR[R8IDX] = (GLubyte)(r * 255.0f);
COLOR[G8IDX] = (GLubyte)(g * 255.0f);
COLOR[B8IDX] = (GLubyte)(b * 255.0f);
}
void APIENTRY glColor4ub(GLubyte r, GLubyte g, GLubyte b, GLubyte a) {
COLOR[0] = r;
COLOR[1] = g;
COLOR[2] = b;
COLOR[3] = a;
IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG;
COLOR[A8IDX] = a;
COLOR[R8IDX] = r;
COLOR[G8IDX] = g;
COLOR[B8IDX] = b;
}
void APIENTRY glColor4ubv(const GLubyte *v) {
IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG;
COLOR[A8IDX] = v[3];
COLOR[R8IDX] = v[0];
COLOR[G8IDX] = v[1];
COLOR[B8IDX] = v[2];
}
void APIENTRY glColor4fv(const GLfloat* v) {
COLOR[0] = (GLubyte)(v[0] * 255);
COLOR[1] = (GLubyte)(v[1] * 255);
COLOR[2] = (GLubyte)(v[2] * 255);
COLOR[3] = (GLubyte)(v[3] * 255);
IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG;
COLOR[B8IDX] = (GLubyte)(v[2] * 255);
COLOR[G8IDX] = (GLubyte)(v[1] * 255);
COLOR[R8IDX] = (GLubyte)(v[0] * 255);
COLOR[A8IDX] = (GLubyte)(v[3] * 255);
}
void APIENTRY glColor3f(GLfloat r, GLfloat g, GLfloat b) {
COLOR[0] = (GLubyte)(r * 255);
COLOR[1] = (GLubyte)(g * 255);
COLOR[2] = (GLubyte)(b * 255);
COLOR[3] = 255;
IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG;
COLOR[B8IDX] = (GLubyte)(b * 255.0f);
COLOR[G8IDX] = (GLubyte)(g * 255.0f);
COLOR[R8IDX] = (GLubyte)(r * 255.0f);
COLOR[A8IDX] = 255;
}
void APIENTRY glColor3ub(GLubyte red, GLubyte green, GLubyte blue) {
COLOR[0] = red;
COLOR[1] = green;
COLOR[2] = blue;
COLOR[3] = 255;
IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG;
COLOR[A8IDX] = 255;
COLOR[R8IDX] = red;
COLOR[G8IDX] = green;
COLOR[B8IDX] = blue;
}
void APIENTRY glColor3ubv(const GLubyte *v) {
COLOR[0] = v[0];
COLOR[1] = v[1];
COLOR[2] = v[2];
COLOR[3] = 255;
IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG;
COLOR[A8IDX] = 255;
COLOR[R8IDX] = v[0];
COLOR[G8IDX] = v[1];
COLOR[B8IDX] = v[2];
}
void APIENTRY glColor3fv(const GLfloat* v) {
COLOR[0] = (GLubyte)(v[0] * 255);
COLOR[1] = (GLubyte)(v[1] * 255);
COLOR[2] = (GLubyte)(v[2] * 255);
COLOR[3] = 255;
}
IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG;
static inline uint32_t pack_vertex_attribute_vec3_1i(float x, float y, float z) {
const float w = 0.0f;
const uint32_t xs = x < 0;
const uint32_t ys = y < 0;
const uint32_t zs = z < 0;
const uint32_t ws = w < 0;
uint32_t vi =
ws << 31 | ((uint32_t)(w + (ws << 1)) & 1) << 30 |
zs << 29 | ((uint32_t)(z * 511 + (zs << 9)) & 511) << 20 |
ys << 19 | ((uint32_t)(y * 511 + (ys << 9)) & 511) << 10 |
xs << 9 | ((uint32_t)(x * 511 + (xs << 9)) & 511);
return vi;
COLOR[A8IDX] = 255;
COLOR[R8IDX] = (GLubyte)(v[0] * 255);
COLOR[G8IDX] = (GLubyte)(v[1] * 255);
COLOR[B8IDX] = (GLubyte)(v[2] * 255);
}
void APIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z) {
GLVertexKOS* vert = aligned_vector_extend(&VERTICES, 1);
GLfloat* st = aligned_vector_extend(&ST_COORDS, 2);
GLuint* n = aligned_vector_extend(&NORMALS, 1);
IM_ENABLED_VERTEX_ATTRIBUTES |= VERTEX_ENABLED_FLAG;
vert->x = x;
vert->y = y;
vert->z = z;
vert->u = UV_COORD[0];
vert->v = UV_COORD[1];
IMVertex* vert = aligned_vector_extend(&VERTICES, 1);
vert->bgra[R8IDX] = COLOR[0];
vert->bgra[G8IDX] = COLOR[1];
vert->bgra[B8IDX] = COLOR[2];
vert->bgra[A8IDX] = COLOR[3];
/* Resizing could've invalidated the pointers */
IM_ATTRIBS.vertex.ptr = VERTICES.data;
IM_ATTRIBS.uv.ptr = IM_ATTRIBS.vertex.ptr + 12;
IM_ATTRIBS.st.ptr = IM_ATTRIBS.uv.ptr + 8;
IM_ATTRIBS.colour.ptr = IM_ATTRIBS.st.ptr + 8;
IM_ATTRIBS.normal.ptr = IM_ATTRIBS.colour.ptr + 4;
*n = pack_vertex_attribute_vec3_1i(NORMAL[0], NORMAL[1], NORMAL[2]);
memcpy(st, ST_COORD, sizeof(GLfloat) * 2);
uint32_t* dest = (uint32_t*) &vert->x;
*(dest++) = *((uint32_t*) &x);
*(dest++) = *((uint32_t*) &y);
*(dest++) = *((uint32_t*) &z);
*(dest++) = *((uint32_t*) &UV_COORD[0]);
*(dest++) = *((uint32_t*) &UV_COORD[1]);
*(dest++) = *((uint32_t*) &ST_COORD[0]);
*(dest++) = *((uint32_t*) &ST_COORD[1]);
*(dest++) = *((uint32_t*) COLOR);
*(dest++) = *((uint32_t*) &NORMAL[0]);
*(dest++) = *((uint32_t*) &NORMAL[1]);
*(dest++) = *((uint32_t*) &NORMAL[2]);
}
void APIENTRY glVertex3fv(const GLfloat* v) {
@ -198,19 +207,31 @@ void APIENTRY glVertex4fv(const GLfloat* v) {
void APIENTRY glMultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t) {
if(target == GL_TEXTURE0) {
IM_ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG;
UV_COORD[0] = s;
UV_COORD[1] = t;
} else if(target == GL_TEXTURE1) {
IM_ENABLED_VERTEX_ATTRIBUTES |= ST_ENABLED_FLAG;
ST_COORD[0] = s;
ST_COORD[1] = t;
} else {
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
return;
}
}
void APIENTRY glTexCoord1f(GLfloat u) {
IM_ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG;
UV_COORD[0] = u;
UV_COORD[1] = 0.0f;
}
void APIENTRY glTexCoord1fv(const GLfloat* v) {
glTexCoord1f(v[0]);
}
void APIENTRY glTexCoord2f(GLfloat u, GLfloat v) {
IM_ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG;
UV_COORD[0] = u;
UV_COORD[1] = v;
}
@ -220,6 +241,7 @@ void APIENTRY glTexCoord2fv(const GLfloat* v) {
}
void APIENTRY glNormal3f(GLfloat x, GLfloat y, GLfloat z) {
IM_ENABLED_VERTEX_ATTRIBUTES |= NORMAL_ENABLED_FLAG;
NORMAL[0] = x;
NORMAL[1] = y;
NORMAL[2] = z;
@ -230,76 +252,40 @@ void APIENTRY glNormal3fv(const GLfloat* v) {
}
void APIENTRY glEnd() {
profiler_push(__func__);
IMMEDIATE_MODE_ACTIVE = GL_FALSE;
/* Resizing could have invalidated these pointers */
VERTEX_ATTRIB.ptr = VERTICES.data + sizeof(uint32_t);
UV_ATTRIB.ptr = VERTEX_ATTRIB.ptr + (sizeof(GLfloat) * 3);
DIFFUSE_ATTRIB.ptr = VERTEX_ATTRIB.ptr + (sizeof(GLfloat) * 5);
GLuint* attrs = &ENABLED_VERTEX_ATTRIBUTES;
NORMAL_ATTRIB.ptr = NORMALS.data;
ST_ATTRIB.ptr = ST_COORDS.data;
GLuint* attrs = _glGetEnabledAttributes();
AttribPointer* vattr = _glGetVertexAttribPointer();
AttribPointer* dattr = _glGetDiffuseAttribPointer();
AttribPointer* nattr = _glGetNormalAttribPointer();
AttribPointer* uattr = _glGetUVAttribPointer();
AttribPointer* sattr = _glGetSTAttribPointer();
/* Stash existing values */
AttribPointer vptr = *vattr;
AttribPointer dptr = *dattr;
AttribPointer nptr = *nattr;
AttribPointer uvptr = *uattr;
AttribPointer stptr = *sattr;
/* Redirect attrib pointers */
AttribPointerList stashed_attrib_pointers = ATTRIB_POINTERS;
ATTRIB_POINTERS = IM_ATTRIBS;
GLuint prevAttrs = *attrs;
/* Switch to our immediate mode arrays */
*vattr = VERTEX_ATTRIB;
*dattr = DIFFUSE_ATTRIB;
*nattr = NORMAL_ATTRIB;
*uattr = UV_ATTRIB;
*sattr = ST_ATTRIB;
*attrs = IM_ENABLED_VERTEX_ATTRIBUTES;
*attrs = ~0; // Enable everything
/* Store the fast path enabled setting so we can restore it
* after drawing */
const GLboolean fp_was_enabled = FAST_PATH_ENABLED;
#ifndef NDEBUG
_glRecalcFastPath();
#else
// Immediate mode should always activate the fast path
GLboolean fastPathEnabled = _glRecalcFastPath();
assert(fastPathEnabled);
GLuint fastPathEnabled = _glRecalcFastPath();
gl_assert(fastPathEnabled);
#else
/* If we're not debugging, set to true - we assume we haven't broken it! */
FAST_PATH_ENABLED = GL_TRUE;
#endif
glDrawArrays(ACTIVE_POLYGON_MODE, 0, VERTICES.size);
glDrawArrays(ACTIVE_POLYGON_MODE, 0, aligned_vector_header(&VERTICES)->size);
/* Restore everything */
*vattr = vptr;
*dattr = dptr;
*nattr = nptr;
*uattr = uvptr;
*sattr = stptr;
ATTRIB_POINTERS = stashed_attrib_pointers;
*attrs = prevAttrs;
/* Clear arrays for next polys */
aligned_vector_clear(&VERTICES);
aligned_vector_clear(&ST_COORDS);
aligned_vector_clear(&NORMALS);
*vattr = vptr;
*dattr = dptr;
*nattr = nptr;
*uattr = uvptr;
*sattr = stptr;
profiler_checkpoint("restore");
profiler_pop();
FAST_PATH_ENABLED = fp_was_enabled;
}
void APIENTRY glRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) {

View File

@ -1,4 +1,3 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
@ -13,126 +12,107 @@
* multiplier ends up less than this value */
#define ATTENUATION_THRESHOLD 100.0f
static GLfloat SCENE_AMBIENT [] = {0.2f, 0.2f, 0.2f, 1.0f};
static GLboolean VIEWER_IN_EYE_COORDINATES = GL_TRUE;
static GLenum COLOR_CONTROL = GL_SINGLE_COLOR;
static GLenum COLOR_MATERIAL_MODE = GL_AMBIENT_AND_DIFFUSE;
#define AMBIENT_MASK 1
#define DIFFUSE_MASK 2
#define EMISSION_MASK 4
#define SPECULAR_MASK 8
#define SCENE_AMBIENT_MASK 16
static GLenum COLOR_MATERIAL_MASK = AMBIENT_MASK | DIFFUSE_MASK;
static LightSource LIGHTS[MAX_LIGHTS];
static GLuint ENABLED_LIGHT_COUNT = 0;
static Material MATERIAL;
GL_FORCE_INLINE void _glPrecalcLightingValues(GLuint mask);
static void recalcEnabledLights() {
GLubyte i;
ENABLED_LIGHT_COUNT = 0;
for(i = 0; i < MAX_LIGHTS; ++i) {
if(LIGHTS[i].isEnabled) {
ENABLED_LIGHT_COUNT++;
}
}
}
void _glInitLights() {
static GLfloat ONE [] = {1.0f, 1.0f, 1.0f, 1.0f};
static GLfloat ZERO [] = {0.0f, 0.0f, 0.0f, 1.0f};
static GLfloat PARTIAL [] = {0.2f, 0.2f, 0.2f, 1.0f};
static GLfloat MOSTLY [] = {0.8f, 0.8f, 0.8f, 1.0f};
memcpy(MATERIAL.ambient, PARTIAL, sizeof(GLfloat) * 4);
memcpy(MATERIAL.diffuse, MOSTLY, sizeof(GLfloat) * 4);
memcpy(MATERIAL.specular, ZERO, sizeof(GLfloat) * 4);
memcpy(MATERIAL.emissive, ZERO, sizeof(GLfloat) * 4);
MATERIAL.exponent = 0.0f;
GLubyte i;
for(i = 0; i < MAX_LIGHTS; ++i) {
memcpy(LIGHTS[i].ambient, ZERO, sizeof(GLfloat) * 4);
memcpy(LIGHTS[i].diffuse, ONE, sizeof(GLfloat) * 4);
memcpy(LIGHTS[i].specular, ONE, sizeof(GLfloat) * 4);
if(i > 0) {
memcpy(LIGHTS[i].diffuse, ZERO, sizeof(GLfloat) * 4);
memcpy(LIGHTS[i].specular, ZERO, sizeof(GLfloat) * 4);
}
LIGHTS[i].position[0] = LIGHTS[i].position[1] = LIGHTS[i].position[3] = 0.0f;
LIGHTS[i].position[2] = 1.0f;
LIGHTS[i].isDirectional = GL_TRUE;
LIGHTS[i].isEnabled = GL_FALSE;
LIGHTS[i].spot_direction[0] = LIGHTS[i].spot_direction[1] = 0.0f;
LIGHTS[i].spot_direction[2] = -1.0f;
LIGHTS[i].spot_exponent = 0.0f;
LIGHTS[i].spot_cutoff = 180.0f;
LIGHTS[i].constant_attenuation = 1.0f;
LIGHTS[i].linear_attenuation = 0.0f;
LIGHTS[i].quadratic_attenuation = 0.0f;
}
_glPrecalcLightingValues(~0);
recalcEnabledLights();
}
void _glEnableLight(GLubyte light, GLboolean value) {
LIGHTS[light].isEnabled = value;
recalcEnabledLights();
}
GL_FORCE_INLINE void _glPrecalcLightingValues(GLuint mask) {
void _glPrecalcLightingValues(GLuint mask) {
/* Pre-calculate lighting values */
GLshort i;
Material* material = _glActiveMaterial();
if(mask & AMBIENT_MASK) {
for(i = 0; i < MAX_LIGHTS; ++i) {
LIGHTS[i].ambientMaterial[0] = LIGHTS[i].ambient[0] * MATERIAL.ambient[0];
LIGHTS[i].ambientMaterial[1] = LIGHTS[i].ambient[1] * MATERIAL.ambient[1];
LIGHTS[i].ambientMaterial[2] = LIGHTS[i].ambient[2] * MATERIAL.ambient[2];
LIGHTS[i].ambientMaterial[3] = LIGHTS[i].ambient[3] * MATERIAL.ambient[3];
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
LightSource* light = _glLightAt(i);
light->ambientMaterial[0] = light->ambient[0] * material->ambient[0];
light->ambientMaterial[1] = light->ambient[1] * material->ambient[1];
light->ambientMaterial[2] = light->ambient[2] * material->ambient[2];
light->ambientMaterial[3] = light->ambient[3] * material->ambient[3];
}
}
if(mask & DIFFUSE_MASK) {
for(i = 0; i < MAX_LIGHTS; ++i) {
LIGHTS[i].diffuseMaterial[0] = LIGHTS[i].diffuse[0] * MATERIAL.diffuse[0];
LIGHTS[i].diffuseMaterial[1] = LIGHTS[i].diffuse[1] * MATERIAL.diffuse[1];
LIGHTS[i].diffuseMaterial[2] = LIGHTS[i].diffuse[2] * MATERIAL.diffuse[2];
LIGHTS[i].diffuseMaterial[3] = LIGHTS[i].diffuse[3] * MATERIAL.diffuse[3];
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
LightSource* light = _glLightAt(i);
light->diffuseMaterial[0] = light->diffuse[0] * material->diffuse[0];
light->diffuseMaterial[1] = light->diffuse[1] * material->diffuse[1];
light->diffuseMaterial[2] = light->diffuse[2] * material->diffuse[2];
light->diffuseMaterial[3] = light->diffuse[3] * material->diffuse[3];
}
}
if(mask & SPECULAR_MASK) {
for(i = 0; i < MAX_LIGHTS; ++i) {
LIGHTS[i].specularMaterial[0] = LIGHTS[i].specular[0] * MATERIAL.specular[0];
LIGHTS[i].specularMaterial[1] = LIGHTS[i].specular[1] * MATERIAL.specular[1];
LIGHTS[i].specularMaterial[2] = LIGHTS[i].specular[2] * MATERIAL.specular[2];
LIGHTS[i].specularMaterial[3] = LIGHTS[i].specular[3] * MATERIAL.specular[3];
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
LightSource* light = _glLightAt(i);
light->specularMaterial[0] = light->specular[0] * material->specular[0];
light->specularMaterial[1] = light->specular[1] * material->specular[1];
light->specularMaterial[2] = light->specular[2] * material->specular[2];
light->specularMaterial[3] = light->specular[3] * material->specular[3];
}
}
/* If ambient or emission are updated, we need to update
* the base colour. */
if((mask & AMBIENT_MASK) || (mask & EMISSION_MASK) || (mask & SCENE_AMBIENT_MASK)) {
MATERIAL.baseColour[0] = MATH_fmac(SCENE_AMBIENT[0], MATERIAL.ambient[0], MATERIAL.emissive[0]);
MATERIAL.baseColour[1] = MATH_fmac(SCENE_AMBIENT[1], MATERIAL.ambient[1], MATERIAL.emissive[1]);
MATERIAL.baseColour[2] = MATH_fmac(SCENE_AMBIENT[2], MATERIAL.ambient[2], MATERIAL.emissive[2]);
MATERIAL.baseColour[3] = MATH_fmac(SCENE_AMBIENT[3], MATERIAL.ambient[3], MATERIAL.emissive[3]);
GLfloat* scene_ambient = _glLightModelSceneAmbient();
material->baseColour[0] = MATH_fmac(scene_ambient[0], material->ambient[0], material->emissive[0]);
material->baseColour[1] = MATH_fmac(scene_ambient[1], material->ambient[1], material->emissive[1]);
material->baseColour[2] = MATH_fmac(scene_ambient[2], material->ambient[2], material->emissive[2]);
material->baseColour[3] = MATH_fmac(scene_ambient[3], material->ambient[3], material->emissive[3]);
}
}
void _glInitLights() {
Material* material = _glActiveMaterial();
static GLfloat ONE [] = {1.0f, 1.0f, 1.0f, 1.0f};
static GLfloat ZERO [] = {0.0f, 0.0f, 0.0f, 1.0f};
static GLfloat PARTIAL [] = {0.2f, 0.2f, 0.2f, 1.0f};
static GLfloat MOSTLY [] = {0.8f, 0.8f, 0.8f, 1.0f};
memcpy(material->ambient, PARTIAL, sizeof(GLfloat) * 4);
memcpy(material->diffuse, MOSTLY, sizeof(GLfloat) * 4);
memcpy(material->specular, ZERO, sizeof(GLfloat) * 4);
memcpy(material->emissive, ZERO, sizeof(GLfloat) * 4);
material->exponent = 0.0f;
GLubyte i;
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
LightSource* light = _glLightAt(i);
memcpy(light->ambient, ZERO, sizeof(GLfloat) * 4);
memcpy(light->diffuse, ONE, sizeof(GLfloat) * 4);
memcpy(light->specular, ONE, sizeof(GLfloat) * 4);
if(i > 0) {
memcpy(light->diffuse, ZERO, sizeof(GLfloat) * 4);
memcpy(light->specular, ZERO, sizeof(GLfloat) * 4);
}
light->position[0] = light->position[1] = light->position[3] = 0.0f;
light->position[2] = 1.0f;
light->isDirectional = GL_TRUE;
light->isEnabled = GL_FALSE;
light->spot_direction[0] = light->spot_direction[1] = 0.0f;
light->spot_direction[2] = -1.0f;
light->spot_exponent = 0.0f;
light->spot_cutoff = 180.0f;
light->constant_attenuation = 1.0f;
light->linear_attenuation = 0.0f;
light->quadratic_attenuation = 0.0f;
}
_glPrecalcLightingValues(~0);
_glRecalcEnabledLights();
}
void APIENTRY glLightModelf(GLenum pname, const GLfloat param) {
glLightModelfv(pname, &param);
}
@ -144,38 +124,39 @@ void APIENTRY glLightModeli(GLenum pname, const GLint param) {
void APIENTRY glLightModelfv(GLenum pname, const GLfloat *params) {
switch(pname) {
case GL_LIGHT_MODEL_AMBIENT: {
memcpy(SCENE_AMBIENT, params, sizeof(GLfloat) * 4);
_glPrecalcLightingValues(SCENE_AMBIENT_MASK);
if(memcmp(_glGetLightModelSceneAmbient(), params, sizeof(float) * 4) != 0) {
_glSetLightModelSceneAmbient(params);
_glPrecalcLightingValues(SCENE_AMBIENT_MASK);
}
} break;
case GL_LIGHT_MODEL_LOCAL_VIEWER:
VIEWER_IN_EYE_COORDINATES = (*params) ? GL_TRUE : GL_FALSE;
_glSetLightModelViewerInEyeCoordinates((*params) ? GL_TRUE : GL_FALSE);
break;
case GL_LIGHT_MODEL_TWO_SIDE:
/* Not implemented */
default:
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
}
}
void APIENTRY glLightModeliv(GLenum pname, const GLint* params) {
switch(pname) {
case GL_LIGHT_MODEL_COLOR_CONTROL:
COLOR_CONTROL = *params;
_glSetLightModelColorControl(*params);
break;
case GL_LIGHT_MODEL_LOCAL_VIEWER:
VIEWER_IN_EYE_COORDINATES = (*params) ? GL_TRUE : GL_FALSE;
_glSetLightModelViewerInEyeCoordinates((*params) ? GL_TRUE : GL_FALSE);
break;
default:
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
}
}
void APIENTRY glLightfv(GLenum light, GLenum pname, const GLfloat *params) {
GLubyte idx = light & 0xF;
if(idx >= MAX_LIGHTS) {
if(idx >= MAX_GLDC_LIGHTS) {
_glKosThrowError(GL_INVALID_VALUE, __func__);
return;
}
@ -183,33 +164,46 @@ void APIENTRY glLightfv(GLenum light, GLenum pname, const GLfloat *params) {
(pname == GL_DIFFUSE) ? DIFFUSE_MASK :
(pname == GL_SPECULAR) ? SPECULAR_MASK : 0;
LightSource* l = _glLightAt(idx);
GLboolean rebuild = GL_FALSE;
switch(pname) {
case GL_AMBIENT:
memcpy(LIGHTS[idx].ambient, params, sizeof(GLfloat) * 4);
rebuild = memcmp(l->ambient, params, sizeof(GLfloat) * 4) != 0;
if(rebuild) {
memcpy(l->ambient, params, sizeof(GLfloat) * 4);
}
break;
case GL_DIFFUSE:
memcpy(LIGHTS[idx].diffuse, params, sizeof(GLfloat) * 4);
rebuild = memcmp(l->diffuse, params, sizeof(GLfloat) * 4) != 0;
if(rebuild) {
memcpy(l->diffuse, params, sizeof(GLfloat) * 4);
}
break;
case GL_SPECULAR:
memcpy(LIGHTS[idx].specular, params, sizeof(GLfloat) * 4);
rebuild = memcmp(l->specular, params, sizeof(GLfloat) * 4) != 0;
if(rebuild) {
memcpy(l->specular, params, sizeof(GLfloat) * 4);
}
break;
case GL_POSITION: {
_glMatrixLoadModelView();
memcpy(LIGHTS[idx].position, params, sizeof(GLfloat) * 4);
memcpy(l->position, params, sizeof(GLfloat) * 4);
LIGHTS[idx].isDirectional = params[3] == 0.0f;
l->isDirectional = params[3] == 0.0f;
if(LIGHTS[idx].isDirectional) {
if(l->isDirectional) {
//FIXME: Do we need to rotate directional lights?
} else {
TransformVec3(LIGHTS[idx].position);
_glMatrixLoadModelView();
TransformVec3(l->position);
}
}
break;
case GL_SPOT_DIRECTION: {
LIGHTS[idx].spot_direction[0] = params[0];
LIGHTS[idx].spot_direction[1] = params[1];
LIGHTS[idx].spot_direction[2] = params[2];
l->spot_direction[0] = params[0];
l->spot_direction[1] = params[1];
l->spot_direction[2] = params[2];
} break;
case GL_CONSTANT_ATTENUATION:
case GL_LINEAR_ATTENUATION:
@ -220,49 +214,52 @@ void APIENTRY glLightfv(GLenum light, GLenum pname, const GLfloat *params) {
break;
default:
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
return;
}
if(rebuild) {
_glPrecalcLightingValues(mask);
}
_glPrecalcLightingValues(mask);
}
void APIENTRY glLightf(GLenum light, GLenum pname, GLfloat param) {
GLubyte idx = light & 0xF;
if(idx >= MAX_LIGHTS) {
if(idx >= MAX_GLDC_LIGHTS) {
_glKosThrowError(GL_INVALID_VALUE, __func__);
return;
}
LightSource* l = _glLightAt(idx);
switch(pname) {
case GL_CONSTANT_ATTENUATION:
LIGHTS[idx].constant_attenuation = param;
l->constant_attenuation = param;
break;
case GL_LINEAR_ATTENUATION:
LIGHTS[idx].linear_attenuation = param;
l->linear_attenuation = param;
break;
case GL_QUADRATIC_ATTENUATION:
LIGHTS[idx].quadratic_attenuation = param;
l->quadratic_attenuation = param;
break;
case GL_SPOT_EXPONENT:
LIGHTS[idx].spot_exponent = param;
l->spot_exponent = param;
break;
case GL_SPOT_CUTOFF:
LIGHTS[idx].spot_cutoff = param;
l->spot_cutoff = param;
break;
default:
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
}
}
void APIENTRY glMaterialf(GLenum face, GLenum pname, const GLfloat param) {
if(face == GL_BACK || pname != GL_SHININESS) {
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
return;
}
MATERIAL.exponent = _MIN(param, 128); /* 128 is the max according to the GL spec */
_glActiveMaterial()->exponent = _MIN(param, 128); /* 128 is the max according to the GL spec */
}
void APIENTRY glMateriali(GLenum face, GLenum pname, const GLint param) {
@ -272,50 +269,74 @@ void APIENTRY glMateriali(GLenum face, GLenum pname, const GLint param) {
void APIENTRY glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) {
if(face == GL_BACK) {
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
return;
}
Material* material = _glActiveMaterial();
GLboolean rebuild = GL_FALSE;
switch(pname) {
case GL_SHININESS:
glMaterialf(face, pname, *params);
rebuild = GL_TRUE;
break;
case GL_AMBIENT:
vec4cpy(MATERIAL.ambient, params);
break;
case GL_AMBIENT: {
if(memcmp(material->ambient, params, sizeof(float) * 4) != 0) {
vec4cpy(material->ambient, params);
rebuild = GL_TRUE;
}
} break;
case GL_DIFFUSE:
vec4cpy(MATERIAL.diffuse, params);
if(memcmp(material->diffuse, params, sizeof(float) * 4) != 0) {
vec4cpy(material->diffuse, params);
rebuild = GL_TRUE;
}
break;
case GL_SPECULAR:
vec4cpy(MATERIAL.specular, params);
if(memcmp(material->specular, params, sizeof(float) * 4) != 0) {
vec4cpy(material->specular, params);
rebuild = GL_TRUE;
}
break;
case GL_EMISSION:
vec4cpy(MATERIAL.emissive, params);
if(memcmp(material->emissive, params, sizeof(float) * 4) != 0) {
vec4cpy(material->emissive, params);
rebuild = GL_TRUE;
}
break;
case GL_AMBIENT_AND_DIFFUSE: {
vec4cpy(MATERIAL.ambient, params);
vec4cpy(MATERIAL.diffuse, params);
rebuild = (
memcmp(material->ambient, params, sizeof(float) * 4) != 0 ||
memcmp(material->diffuse, params, sizeof(float) * 4) != 0
);
if(rebuild) {
vec4cpy(material->ambient, params);
vec4cpy(material->diffuse, params);
}
} break;
case GL_COLOR_INDEXES:
default: {
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
return;
}
}
GLuint updateMask = (pname == GL_AMBIENT) ? AMBIENT_MASK:
(pname == GL_DIFFUSE) ? DIFFUSE_MASK:
(pname == GL_SPECULAR) ? SPECULAR_MASK:
(pname == GL_EMISSION) ? EMISSION_MASK:
(pname == GL_AMBIENT_AND_DIFFUSE) ? AMBIENT_MASK | DIFFUSE_MASK : 0;
if(rebuild) {
GLuint updateMask = (pname == GL_AMBIENT) ? AMBIENT_MASK:
(pname == GL_DIFFUSE) ? DIFFUSE_MASK:
(pname == GL_SPECULAR) ? SPECULAR_MASK:
(pname == GL_EMISSION) ? EMISSION_MASK:
(pname == GL_AMBIENT_AND_DIFFUSE) ? AMBIENT_MASK | DIFFUSE_MASK : 0;
_glPrecalcLightingValues(updateMask);
_glPrecalcLightingValues(updateMask);
}
}
void APIENTRY glColorMaterial(GLenum face, GLenum mode) {
if(face != GL_FRONT_AND_BACK) {
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
return;
}
@ -325,12 +346,13 @@ void APIENTRY glColorMaterial(GLenum face, GLenum mode) {
return;
}
COLOR_MATERIAL_MASK = (mode == GL_AMBIENT) ? AMBIENT_MASK:
GLenum mask = (mode == GL_AMBIENT) ? AMBIENT_MASK:
(mode == GL_DIFFUSE) ? DIFFUSE_MASK:
(mode == GL_AMBIENT_AND_DIFFUSE) ? AMBIENT_MASK | DIFFUSE_MASK:
(mode == GL_EMISSION) ? EMISSION_MASK : SPECULAR_MASK;
COLOR_MATERIAL_MODE = mode;
_glSetColorMaterialMask(mask);
_glSetColorMaterialMode(mode);
}
GL_FORCE_INLINE void bgra_to_float(const uint8_t* input, GLfloat* output) {
@ -343,44 +365,68 @@ GL_FORCE_INLINE void bgra_to_float(const uint8_t* input, GLfloat* output) {
}
void _glUpdateColourMaterialA(const GLubyte* argb) {
Material* material = _glActiveMaterial();
float colour[4];
bgra_to_float(argb, colour);
vec4cpy(MATERIAL.ambient, colour);
_glPrecalcLightingValues(COLOR_MATERIAL_MASK);
vec4cpy(material->ambient, colour);
GLenum mask = _glColorMaterialMode();
_glPrecalcLightingValues(mask);
}
void _glUpdateColourMaterialD(const GLubyte* argb) {
Material* material = _glActiveMaterial();
float colour[4];
bgra_to_float(argb, colour);
vec4cpy(MATERIAL.diffuse, colour);
_glPrecalcLightingValues(COLOR_MATERIAL_MASK);
vec4cpy(material->diffuse, colour);
GLenum mask = _glColorMaterialMode();
_glPrecalcLightingValues(mask);
}
void _glUpdateColourMaterialE(const GLubyte* argb) {
Material* material = _glActiveMaterial();
float colour[4];
bgra_to_float(argb, colour);
vec4cpy(MATERIAL.emissive, colour);
_glPrecalcLightingValues(COLOR_MATERIAL_MASK);
vec4cpy(material->emissive, colour);
GLenum mask = _glColorMaterialMode();
_glPrecalcLightingValues(mask);
}
void _glUpdateColourMaterialAD(const GLubyte* argb) {
Material* material = _glActiveMaterial();
float colour[4];
bgra_to_float(argb, colour);
vec4cpy(MATERIAL.ambient, colour);
vec4cpy(MATERIAL.diffuse, colour);
_glPrecalcLightingValues(COLOR_MATERIAL_MASK);
vec4cpy(material->ambient, colour);
vec4cpy(material->diffuse, colour);
GLenum mask = _glColorMaterialMode();
_glPrecalcLightingValues(mask);
}
GL_FORCE_INLINE GLboolean isDiffuseColorMaterial() {
return (COLOR_MATERIAL_MODE == GL_DIFFUSE || COLOR_MATERIAL_MODE == GL_AMBIENT_AND_DIFFUSE);
GLenum mode = _glColorMaterialMode();
return (
mode == GL_DIFFUSE ||
mode == GL_AMBIENT_AND_DIFFUSE
);
}
GL_FORCE_INLINE GLboolean isAmbientColorMaterial() {
return (COLOR_MATERIAL_MODE == GL_AMBIENT || COLOR_MATERIAL_MODE == GL_AMBIENT_AND_DIFFUSE);
GLenum mode = _glColorMaterialMode();
return (
mode == GL_AMBIENT ||
mode == GL_AMBIENT_AND_DIFFUSE
);
}
GL_FORCE_INLINE GLboolean isSpecularColorMaterial() {
return (COLOR_MATERIAL_MODE == GL_SPECULAR);
GLenum mode = _glColorMaterialMode();
return (mode == GL_SPECULAR);
}
/*
@ -399,7 +445,7 @@ GL_FORCE_INLINE float faster_pow2(const float p) {
}
GL_FORCE_INLINE float faster_log2(const float x) {
assert(x >= 0.0f);
gl_assert(x >= 0.0f);
const union { float f; uint32_t i; } vx = { x };
const float y = (float) (vx.i) * 1.1920928955078125e-7f;
@ -415,12 +461,15 @@ GL_FORCE_INLINE void _glLightVertexDirectional(
float* final, uint8_t lid,
float LdotN, float NdotH) {
float FI = (MATERIAL.exponent) ?
faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f;
Material* material = _glActiveMaterial();
LightSource* light = _glLightAt(lid);
float FI = (material->exponent) ?
faster_pow((LdotN != 0.0f) * NdotH, material->exponent) : 1.0f;
#define _PROCESS_COMPONENT(X) \
final[X] += (LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \
+ (FI * LIGHTS[lid].specularMaterial[X]); \
final[X] += (LdotN * light->diffuseMaterial[X] + light->ambientMaterial[X]) \
+ (FI * light->specularMaterial[X]); \
_PROCESS_COMPONENT(0);
_PROCESS_COMPONENT(1);
@ -433,12 +482,15 @@ GL_FORCE_INLINE void _glLightVertexPoint(
float* final, uint8_t lid,
float LdotN, float NdotH, float att) {
float FI = (MATERIAL.exponent) ?
faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f;
Material* material = _glActiveMaterial();
LightSource* light = _glLightAt(lid);
float FI = (material->exponent) ?
faster_pow((LdotN != 0.0f) * NdotH, material->exponent) : 1.0f;
#define _PROCESS_COMPONENT(X) \
final[X] += ((LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \
+ (FI * LIGHTS[lid].specularMaterial[X])) * att; \
final[X] += ((LdotN * light->diffuseMaterial[X] + light->ambientMaterial[X]) \
+ (FI * light->specularMaterial[X])) * att; \
_PROCESS_COMPONENT(0);
_PROCESS_COMPONENT(1);
@ -451,6 +503,8 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
GLubyte i;
GLuint j;
Material* material = _glActiveMaterial();
Vertex* vertex = vertices;
EyeSpaceData* data = es;
@ -458,7 +512,8 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
void (*updateColourMaterial)(const GLubyte*) = NULL;
if(_glIsColorMaterialEnabled()) {
switch(COLOR_MATERIAL_MODE) {
GLenum mode = _glColorMaterialMode();
switch(mode) {
case GL_AMBIENT:
updateColourMaterial = _glUpdateColourMaterialA;
break;
@ -481,10 +536,10 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
}
/* Copy the base colour across */
vec4cpy(data->finalColour, MATERIAL.baseColour);
vec4cpy(data->finalColour, material->baseColour);
}
if(!ENABLED_LIGHT_COUNT) {
if(!_glEnabledLightCount()) {
return;
}
@ -492,25 +547,27 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
data = es;
for(j = 0; j < count; ++j, ++vertex, ++data) {
/* Direction to vertex in eye space */
float Vx = -data->xyz[0];
float Vy = -data->xyz[1];
float Vz = -data->xyz[2];
float Vx = -vertex->xyz[0];
float Vy = -vertex->xyz[1];
float Vz = -vertex->xyz[2];
VEC3_NORMALIZE(Vx, Vy, Vz);
const float Nx = data->n[0];
const float Ny = data->n[1];
const float Nz = data->n[2];
for(i = 0; i < MAX_LIGHTS; ++i) {
if(!LIGHTS[i].isEnabled) {
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
LightSource* light = _glLightAt(i);
if(!light->isEnabled) {
continue;
}
float Lx = LIGHTS[i].position[0] - data->xyz[0];
float Ly = LIGHTS[i].position[1] - data->xyz[1];
float Lz = LIGHTS[i].position[2] - data->xyz[2];
float Lx = light->position[0] - vertex->xyz[0];
float Ly = light->position[1] - vertex->xyz[1];
float Lz = light->position[2] - vertex->xyz[2];
if(LIGHTS[i].isDirectional) {
if(light->isDirectional) {
float Hx = (Lx + 0);
float Hy = (Ly + 0);
float Hz = (Lz + 1);
@ -539,9 +596,9 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
VEC3_LENGTH(Lx, Ly, Lz, D);
float att = (
LIGHTS[i].constant_attenuation + (
LIGHTS[i].linear_attenuation * D
) + (LIGHTS[i].quadratic_attenuation * D * D)
light->constant_attenuation + (
light->linear_attenuation * D
) + (light->quadratic_attenuation * D * D)
);
/* Anything over the attenuation threshold will

View File

@ -13,17 +13,17 @@
GLfloat DEPTH_RANGE_MULTIPLIER_L = (1 - 0) / 2;
GLfloat DEPTH_RANGE_MULTIPLIER_H = (0 + 1) / 2;
/* Viewport size */
static GLint gl_viewport_x1, gl_viewport_y1, gl_viewport_width, gl_viewport_height;
static Stack __attribute__((aligned(32))) MATRIX_STACKS[4]; // modelview, projection, texture
static Matrix4x4 __attribute__((aligned(32))) NORMAL_MATRIX;
static Stack MATRIX_STACKS[3]; // modelview, projection, texture
static Matrix4x4 NORMAL_MATRIX __attribute__((aligned(32)));
static Matrix4x4 SCREENVIEW_MATRIX __attribute__((aligned(32)));
Viewport VIEWPORT = {
0, 0, 640, 480, 320.0f, 240.0f, 320.0f, 240.0f
};
static GLenum MATRIX_MODE = GL_MODELVIEW;
static GLubyte MATRIX_IDX = 0;
static const Matrix4x4 IDENTITY = {
static const Matrix4x4 __attribute__((aligned(32))) IDENTITY = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
@ -49,8 +49,7 @@ void _glInitMatrices() {
stack_push(&MATRIX_STACKS[1], IDENTITY);
stack_push(&MATRIX_STACKS[2], IDENTITY);
FASTCPY4(NORMAL_MATRIX, IDENTITY, sizeof(Matrix4x4));
FASTCPY4(SCREENVIEW_MATRIX, IDENTITY, sizeof(Matrix4x4));
MEMCPY4(NORMAL_MATRIX, IDENTITY, sizeof(Matrix4x4));
const VideoMode* vid_mode = GetVideoMode();
@ -96,7 +95,7 @@ static void transpose(GLfloat* m) {
}
static void recalculateNormalMatrix() {
FASTCPY4(NORMAL_MATRIX, stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)), sizeof(Matrix4x4));
MEMCPY4(NORMAL_MATRIX, stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)), sizeof(Matrix4x4));
inverse((GLfloat*) NORMAL_MATRIX);
transpose((GLfloat*) NORMAL_MATRIX);
}
@ -107,7 +106,11 @@ void APIENTRY glMatrixMode(GLenum mode) {
}
void APIENTRY glPushMatrix() {
stack_push(MATRIX_STACKS + MATRIX_IDX, stack_top(MATRIX_STACKS + MATRIX_IDX));
void* top = stack_top(MATRIX_STACKS + MATRIX_IDX);
assert(top);
void* ret = stack_push(MATRIX_STACKS + MATRIX_IDX, top);
(void) ret;
assert(ret);
}
void APIENTRY glPopMatrix() {
@ -128,10 +131,16 @@ void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
0.0f, 0.0f, 1.0f, 0.0f,
x, y, z, 1.0f
};
void* top = stack_top(MATRIX_STACKS + MATRIX_IDX);
assert(top);
UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX));
UploadMatrix4x4(top);
MultiplyMatrix4x4(&trn);
DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX));
top = stack_top(MATRIX_STACKS + MATRIX_IDX);
assert(top);
DownloadMatrix4x4(top);
if(MATRIX_MODE == GL_MODELVIEW) {
recalculateNormalMatrix();
@ -201,28 +210,9 @@ void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
/* Load an arbitrary matrix */
void APIENTRY glLoadMatrixf(const GLfloat *m) {
static Matrix4x4 TEMP;
TEMP[M0] = m[0];
TEMP[M1] = m[1];
TEMP[M2] = m[2];
TEMP[M3] = m[3];
TEMP[M4] = m[4];
TEMP[M5] = m[5];
TEMP[M6] = m[6];
TEMP[M7] = m[7];
TEMP[M8] = m[8];
TEMP[M9] = m[9];
TEMP[M10] = m[10];
TEMP[M11] = m[11];
TEMP[M12] = m[12];
TEMP[M13] = m[13];
TEMP[M14] = m[14];
TEMP[M15] = m[15];
static Matrix4x4 __attribute__((aligned(32))) TEMP;
memcpy(TEMP, m, sizeof(float) * 16);
stack_replace(MATRIX_STACKS + MATRIX_IDX, TEMP);
if(MATRIX_MODE == GL_MODELVIEW) {
@ -289,11 +279,11 @@ void APIENTRY glFrustum(GLfloat left, GLfloat right,
/* Multiply the current matrix by an arbitrary matrix */
void glMultMatrixf(const GLfloat *m) {
Matrix4x4 TEMP;
FASTCPY4(TEMP, m, sizeof(Matrix4x4));
Matrix4x4 TEMP __attribute__((aligned(32)));
MEMCPY4(TEMP, m, sizeof(Matrix4x4));
UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX));
MultiplyMatrix4x4((const Matrix4x4*) &TEMP);
MultiplyMatrix4x4(&TEMP);
DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX));
if(MATRIX_MODE == GL_MODELVIEW) {
@ -370,22 +360,14 @@ void glMultTransposeMatrixf(const GLfloat *m) {
/* Set the GL viewport */
void APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
const VideoMode* vid_mode = GetVideoMode();
gl_viewport_x1 = x;
gl_viewport_y1 = y;
gl_viewport_width = width;
gl_viewport_height = height;
GLfloat hw = ((GLfloat) width) / 2.0f;
GLfloat hh = ((GLfloat) height) / 2.0f;
y *= -1; // Flip
SCREENVIEW_MATRIX[M0] = hw;
SCREENVIEW_MATRIX[M5] = -hh;
SCREENVIEW_MATRIX[M10] = 1;
SCREENVIEW_MATRIX[M12] = hw + x;
SCREENVIEW_MATRIX[M13] = vid_mode->height - hh + y;
VIEWPORT.x = x;
VIEWPORT.y = y;
VIEWPORT.width = width;
VIEWPORT.height = height;
VIEWPORT.hwidth = ((GLfloat) VIEWPORT.width) * 0.5f;
VIEWPORT.hheight = ((GLfloat) VIEWPORT.height) * 0.5f;
VIEWPORT.x_plus_hwidth = VIEWPORT.x + VIEWPORT.hwidth;
VIEWPORT.y_plus_hheight = VIEWPORT.y + VIEWPORT.hheight;
}
/* Set the depth range */
@ -427,7 +409,7 @@ GL_FORCE_INLINE void vec3f_normalize_sh4(float *v){
void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx,
GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy,
GLfloat upz) {
GLfloat m [16];
GLfloat m [16] __attribute__((aligned(32)));
GLfloat f [3];
GLfloat u [3];
GLfloat s [3];
@ -468,12 +450,6 @@ void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx,
DownloadMatrix4x4(stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)));
}
void _glApplyRenderMatrix() {
UploadMatrix4x4((const Matrix4x4*) &SCREENVIEW_MATRIX);
MultiplyMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF)));
MultiplyMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)));
}
void _glMatrixLoadTexture() {
UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_TEXTURE & 0xF)));
}
@ -482,6 +458,15 @@ void _glMatrixLoadModelView() {
UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)));
}
void _glMatrixLoadProjection() {
UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF)));
}
void _glMatrixLoadModelViewProjection() {
UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF)));
MultiplyMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)));
}
void _glMatrixLoadNormal() {
UploadMatrix4x4((const Matrix4x4*) &NORMAL_MATRIX);
}

View File

@ -3,7 +3,9 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include "gl_assert.h"
#include "types.h"
#define MEMSET(dst, v, size) memset((dst), (v), (size))
@ -259,7 +261,7 @@ typedef float Matrix4x4[16];
void SceneBegin();
void SceneListBegin(GPUList list);
void SceneListSubmit(void* src, int n);
void SceneListSubmit(Vertex* v2, int n);
void SceneListFinish();
void SceneFinish();
@ -354,9 +356,23 @@ void SceneFinish();
#define GPU_TA_PM3_TXRFMT_SHIFT 0
#define GPU_TA_PM3_TXRFMT_MASK 0xffffffff
static inline int DimensionFlag(const int w) {
switch(w) {
case 16: return 1;
case 32: return 2;
case 64: return 3;
case 128: return 4;
case 256: return 5;
case 512: return 6;
case 1024: return 7;
case 8:
default:
return 0;
}
}
/* Compile a polygon context into a polygon header */
static inline void CompilePolyHeader(PolyHeader *dst, const PolyContext *src) {
int u, v;
uint32_t txr_base;
/* Basically we just take each parameter, clip it, shift it
@ -365,8 +381,7 @@ static inline void CompilePolyHeader(PolyHeader *dst, const PolyContext *src) {
/* The base values for CMD */
dst->cmd = GPU_CMD_POLYHDR;
if(src->txr.enable == GPU_TEXTURE_ENABLE)
dst->cmd |= 8;
dst->cmd |= src->txr.enable << 3;
/* Or in the list type, shading type, color and UV formats */
dst->cmd |= (src->list_type << GPU_TA_CMD_TYPE_SHIFT) & GPU_TA_CMD_TYPE_MASK;
@ -404,70 +419,8 @@ static inline void CompilePolyHeader(PolyHeader *dst, const PolyContext *src) {
dst->mode2 |= (src->txr.mipmap_bias << GPU_TA_PM2_MIPBIAS_SHIFT) & GPU_TA_PM2_MIPBIAS_MASK;
dst->mode2 |= (src->txr.env << GPU_TA_PM2_TXRENV_SHIFT) & GPU_TA_PM2_TXRENV_MASK;
switch(src->txr.width) {
case 8:
u = 0;
break;
case 16:
u = 1;
break;
case 32:
u = 2;
break;
case 64:
u = 3;
break;
case 128:
u = 4;
break;
case 256:
u = 5;
break;
case 512:
u = 6;
break;
case 1024:
u = 7;
break;
default:
assert(0 && "Invalid texture U size");
u = 0;
break;
}
switch(src->txr.height) {
case 8:
v = 0;
break;
case 16:
v = 1;
break;
case 32:
v = 2;
break;
case 64:
v = 3;
break;
case 128:
v = 4;
break;
case 256:
v = 5;
break;
case 512:
v = 6;
break;
case 1024:
v = 7;
break;
default:
assert(0 && "Invalid texture V size");
v = 0;
break;
}
dst->mode2 |= (u << GPU_TA_PM2_USIZE_SHIFT) & GPU_TA_PM2_USIZE_MASK;
dst->mode2 |= (v << GPU_TA_PM2_VSIZE_SHIFT) & GPU_TA_PM2_VSIZE_MASK;
dst->mode2 |= (DimensionFlag(src->txr.width) << GPU_TA_PM2_USIZE_SHIFT) & GPU_TA_PM2_USIZE_MASK;
dst->mode2 |= (DimensionFlag(src->txr.height) << GPU_TA_PM2_VSIZE_SHIFT) & GPU_TA_PM2_VSIZE_MASK;
/* Polygon mode 3 */
dst->mode3 = (src->txr.mipmap << GPU_TA_PM3_MIPMAP_SHIFT) & GPU_TA_PM3_MIPMAP_MASK;

View File

@ -1,13 +1,25 @@
#include "../platform.h"
#include "sh4.h"
#define TA_SQ_ADDR (unsigned int *)(void *) \
(0xe0000000 | (((unsigned long)0x10000000) & 0x03ffffe0))
#define QACRTA ((((unsigned int)0x10000000)>>26)<<2)&0x1c
#define CLIP_DEBUG 0
#define PVR_VERTEX_BUF_SIZE 2560 * 256
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define SQ_BASE_ADDRESS (void*) 0xe0000000
GL_FORCE_INLINE bool glIsVertex(const float flags) {
return flags == GPU_CMD_VERTEX_EOL || flags == GPU_CMD_VERTEX;
}
GL_FORCE_INLINE bool glIsLastVertex(const float flags) {
return flags == GPU_CMD_VERTEX_EOL;
}
void InitGPU(_Bool autosort, _Bool fsaa) {
pvr_init_params_t params = {
/* Enable opaque and translucent polygons with size 32 and 32 */
@ -19,41 +31,427 @@ void InitGPU(_Bool autosort, _Bool fsaa) {
};
pvr_init(&params);
/* If we're PAL and we're NOT VGA, then use 50hz by default. This is the safest
thing to do. If someone wants to force 60hz then they can call vid_set_mode later and hopefully
that'll work... */
int cable = vid_check_cable();
int region = flashrom_get_region();
if(region == FLASHROM_REGION_EUROPE && cable != CT_VGA) {
printf("PAL region without VGA - enabling 50hz");
vid_set_mode(DM_640x480_PAL_IL, PM_RGB565);
}
}
void SceneBegin() {
pvr_wait_ready();
pvr_scene_begin();
QACR0 = QACRTA;
QACR1 = QACRTA;
}
void SceneListBegin(GPUList list) {
pvr_list_begin(list);
}
void SceneListSubmit(void* src, int n) {
uint32_t *d = (uint32_t*) TA_SQ_ADDR;
uint32_t *s = src;
GL_FORCE_INLINE float _glFastInvert(float x) {
return (1.f / __builtin_sqrtf(x * x));
}
/* fill/write queues as many times necessary */
while(n--) {
__asm__("pref @%0" : : "r"(s + 8)); /* prefetch 32 bytes for next loop */
d[0] = *(s++);
d[1] = *(s++);
d[2] = *(s++);
d[3] = *(s++);
d[4] = *(s++);
d[5] = *(s++);
d[6] = *(s++);
d[7] = *(s++);
__asm__("pref @%0" : : "r"(d));
d += 8;
GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) {
TRACE();
const float f = _glFastInvert(vertex->w);
/* Convert to NDC and apply viewport */
vertex->xyz[0] = (vertex->xyz[0] * f * 320) + 320;
vertex->xyz[1] = (vertex->xyz[1] * f * -240) + 240;
/* Orthographic projections need to use invZ otherwise we lose
the depth information. As w == 1, and clip-space range is -w to +w
we add 1.0 to the Z to bring it into range. We add a little extra to
avoid a divide by zero.
*/
if(vertex->w == 1.0f) {
vertex->xyz[2] = _glFastInvert(1.0001f + vertex->xyz[2]);
} else {
vertex->xyz[2] = f;
}
}
volatile uint32_t *sq = SQ_BASE_ADDRESS;
static inline void _glFlushBuffer() {
TRACE();
/* Wait for both store queues to complete */
d = (uint32_t *)0xe0000000;
d[0] = d[8] = 0;
sq = (uint32_t*) 0xe0000000;
sq[0] = sq[8] = 0;
}
static inline void _glPushHeaderOrVertex(Vertex* v) {
TRACE();
uint32_t* s = (uint32_t*) v;
sq[0] = *(s++);
sq[1] = *(s++);
sq[2] = *(s++);
sq[3] = *(s++);
sq[4] = *(s++);
sq[5] = *(s++);
sq[6] = *(s++);
sq[7] = *(s++);
__asm__("pref @%0" : : "r"(sq));
sq += 8;
}
static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, Vertex* vout) {
const static float o = 0.003921569f; // 1 / 255
const float d0 = v1->w + v1->xyz[2];
const float d1 = v2->w + v2->xyz[2];
const float t = (fabs(d0) * (1.0f / sqrtf((d1 - d0) * (d1 - d0)))) + 0.000001f;
const float invt = 1.0f - t;
vout->xyz[0] = invt * v1->xyz[0] + t * v2->xyz[0];
vout->xyz[1] = invt * v1->xyz[1] + t * v2->xyz[1];
vout->xyz[2] = invt * v1->xyz[2] + t * v2->xyz[2];
vout->uv[0] = invt * v1->uv[0] + t * v2->uv[0];
vout->uv[1] = invt * v1->uv[1] + t * v2->uv[1];
vout->w = invt * v1->w + t * v2->w;
const float m = 255 * t;
const float n = 255 - m;
vout->bgra[0] = (v1->bgra[0] * n + v2->bgra[0] * m) * o;
vout->bgra[1] = (v1->bgra[1] * n + v2->bgra[1] * m) * o;
vout->bgra[2] = (v1->bgra[2] * n + v2->bgra[2] * m) * o;
vout->bgra[3] = (v1->bgra[3] * n + v2->bgra[3] * m) * o;
}
#define SPAN_SORT_CFG 0x005F8030
static volatile uint32_t* PVR_LMMODE0 = (uint32_t*) 0xA05F6884;
static volatile uint32_t *PVR_LMMODE1 = (uint32_t*) 0xA05F6888;
static volatile uint32_t *QACR = (uint32_t*) 0xFF000038;
void SceneListSubmit(Vertex* v2, int n) {
TRACE();
/* You need at least a header, and 3 vertices to render anything */
if(n < 4) {
return;
}
const float h = GetVideoMode()->height;
PVR_SET(SPAN_SORT_CFG, 0x0);
//Set PVR DMA registers
*PVR_LMMODE0 = 0;
*PVR_LMMODE1 = 0;
//Set QACR registers
QACR[1] = QACR[0] = 0x11;
#if CLIP_DEBUG
Vertex* vertex = (Vertex*) src;
for(int i = 0; i < n; ++i) {
fprintf(stderr, "{%f, %f, %f, %f}, // %x (%x)\n", vertex[i].xyz[0], vertex[i].xyz[1], vertex[i].xyz[2], vertex[i].w, vertex[i].flags, &vertex[i]);
}
fprintf(stderr, "----\n");
#endif
uint8_t visible_mask = 0;
uint8_t counter = 0;
sq = SQ_BASE_ADDRESS;
for(int i = 0; i < n; ++i, ++v2) {
PREFETCH(v2 + 1);
switch(v2->flags) {
case GPU_CMD_VERTEX_EOL:
if(counter < 2) {
continue;
}
counter = 0;
break;
case GPU_CMD_VERTEX:
++counter;
if(counter < 3) {
continue;
}
break;
default:
_glPushHeaderOrVertex(v2);
counter = 0;
continue;
};
Vertex* const v0 = v2 - 2;
Vertex* const v1 = v2 - 1;
visible_mask = (
(v0->xyz[2] > -v0->w) << 0 |
(v1->xyz[2] > -v1->w) << 1 |
(v2->xyz[2] > -v2->w) << 2 |
(counter == 0) << 3
);
switch(visible_mask) {
case 15: /* All visible, but final vertex in strip */
{
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(v1, h);
_glPushHeaderOrVertex(v1);
_glPerspectiveDivideVertex(v2, h);
_glPushHeaderOrVertex(v2);
}
break;
case 7:
/* All visible, push the first vertex and move on */
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
break;
case 9:
/* First vertex was visible, last in strip */
{
Vertex __attribute__((aligned(32))) scratch[2];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v2, v0, b);
b->flags = GPU_CMD_VERTEX_EOL;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
}
break;
case 1:
/* First vertex was visible, but not last in strip */
{
Vertex __attribute__((aligned(32))) scratch[2];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v2, v0, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPushHeaderOrVertex(b);
}
break;
case 10:
case 2:
/* Second vertex was visible. In self case we need to create a triangle and produce
two new vertices: 1-2, and 2-3. */
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v1);
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v1, v2, b);
b->flags = v2->flags;
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
}
break;
case 11:
case 3: /* First and second vertex were visible */
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v1);
_glClipEdge(v2, v0, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glClipEdge(v1, v2, a);
a->flags = v2->flags;
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(c);
_glPushHeaderOrVertex(a);
}
break;
case 12:
case 4:
/* Third vertex was visible. */
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v2);
_glClipEdge(v2, v0, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v1, v2, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
if(counter % 2 == 1) {
_glPushHeaderOrVertex(a);
}
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
}
break;
case 13:
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v2);
c->flags = GPU_CMD_VERTEX;
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v1, v2, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
c->flags = GPU_CMD_VERTEX_EOL;
_glPushHeaderOrVertex(c);
}
break;
case 5: /* First and third vertex were visible */
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v2);
c->flags = GPU_CMD_VERTEX;
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v1, v2, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPushHeaderOrVertex(c);
}
break;
case 14:
case 6: /* Second and third vertex were visible */
{
Vertex __attribute__((aligned(32))) scratch[4];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
Vertex* d = &scratch[3];
memcpy_vertex(c, v1);
memcpy_vertex(d, v2);
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v2, v0, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(d, h);
_glPushHeaderOrVertex(d);
}
break;
case 8:
default:
break;
}
}
_glFlushBuffer();
}
void SceneListFinish() {

View File

@ -8,13 +8,66 @@
#include <dc/matrix3d.h>
#include "../types.h"
#include "../private.h"
#include "sh4_math.h"
#define FASTCPY(dst, src, bytes) \
(bytes % 32 == 0) ? sq_cpy(dst, src, bytes) : memcpy(dst, src, bytes)
#ifndef NDEBUG
#define PERF_WARNING(msg) printf("[PERF] %s\n", msg)
#else
#define PERF_WARNING(msg) (void) 0
#endif
#define FASTCPY4(dst, src, bytes) \
(bytes % 32 == 0) ? sq_cpy(dst, src, bytes) : memcpy4(dst, src, bytes)
#ifndef GL_FORCE_INLINE
#define GL_NO_INSTRUMENT inline __attribute__((no_instrument_function))
#define GL_INLINE_DEBUG GL_NO_INSTRUMENT __attribute__((always_inline))
#define GL_FORCE_INLINE static GL_INLINE_DEBUG
#endif
#define PREFETCH(addr) __builtin_prefetch((addr))
GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) {
if(!len) {
return dest;
}
const uint8_t *s = (uint8_t *)src;
uint8_t *d = (uint8_t *)dest;
uint32_t diff = (uint32_t)d - (uint32_t)(s + 1); // extra offset because input gets incremented before output is calculated
// Underflow would be like adding a negative offset
// Can use 'd' as a scratch reg now
asm volatile (
"clrs\n" // Align for parallelism (CO) - SH4a use "stc SR, Rn" instead with a dummy Rn
".align 2\n"
"0:\n\t"
"dt %[size]\n\t" // (--len) ? 0 -> T : 1 -> T (EX 1)
"mov.b @%[in]+, %[scratch]\n\t" // scratch = *(s++) (LS 1/2)
"bf.s 0b\n\t" // while(s != nexts) aka while(!T) (BR 1/2)
" mov.b %[scratch], @(%[offset], %[in])\n" // *(datatype_of_s*) ((char*)s + diff) = scratch, where src + diff = dest (LS 1)
: [in] "+&r" ((uint32_t)s), [scratch] "=&r" ((uint32_t)d), [size] "+&r" (len) // outputs
: [offset] "z" (diff) // inputs
: "t", "memory" // clobbers
);
return dest;
}
/* We use sq_cpy if the src and size is properly aligned. We control that the
* destination is properly aligned so we assert that. */
#define FASTCPY(dst, src, bytes) \
do { \
if(bytes % 32 == 0 && ((uintptr_t) src % 4) == 0) { \
gl_assert(((uintptr_t) dst) % 32 == 0); \
sq_cpy(dst, src, bytes); \
} else { \
memcpy_fast(dst, src, bytes); \
} \
} while(0)
#define MEMCPY4(dst, src, bytes) memcpy_fast(dst, src, bytes)
#define MEMSET4(dst, v, size) memset4((dst), (v), (size))
@ -22,29 +75,29 @@
#define VEC3_LENGTH(x, y, z, l) vec3f_length((x), (y), (z), (l))
#define VEC3_DOT(x1, y1, z1, x2, y2, z2, d) vec3f_dot((x1), (y1), (z1), (x2), (y2), (z2), (d))
static inline void UploadMatrix4x4(const Matrix4x4* mat) {
GL_FORCE_INLINE void UploadMatrix4x4(const Matrix4x4* mat) {
mat_load((matrix_t*) mat);
}
static inline void DownloadMatrix4x4(Matrix4x4* mat) {
GL_FORCE_INLINE void DownloadMatrix4x4(Matrix4x4* mat) {
mat_store((matrix_t*) mat);
}
static inline void MultiplyMatrix4x4(const Matrix4x4* mat) {
GL_FORCE_INLINE void MultiplyMatrix4x4(const Matrix4x4* mat) {
mat_apply((matrix_t*) mat);
}
static inline void TransformVec3(float* x) {
GL_FORCE_INLINE void TransformVec3(float* x) {
mat_trans_single4(x[0], x[1], x[2], x[3]);
}
/* Transform a 3-element vector using the stored matrix (w == 1) */
static inline void TransformVec3NoMod(const float* xIn, float* xOut) {
GL_FORCE_INLINE void TransformVec3NoMod(const float* xIn, float* xOut) {
mat_trans_single3_nodiv_nomod(xIn[0], xIn[1], xIn[2], xOut[0], xOut[1], xOut[2]);
}
/* Transform a 3-element normal using the stored matrix (w == 0)*/
static inline void TransformNormalNoMod(const float* in, float* out) {
GL_FORCE_INLINE void TransformNormalNoMod(const float* in, float* out) {
mat_trans_normal3_nomod(in[0], in[1], in[2], out[0], out[1], out[2]);
}
@ -53,6 +106,25 @@ inline void TransformVec4(float* x) {
}
GL_FORCE_INLINE void TransformVertex(const float* xyz, const float* w, float* oxyz, float* ow) {
register float __x __asm__("fr12") = (xyz[0]);
register float __y __asm__("fr13") = (xyz[1]);
register float __z __asm__("fr14") = (xyz[2]);
register float __w __asm__("fr15") = (*w);
__asm__ __volatile__(
"fldi1 fr15\n"
"ftrv xmtrx,fv12\n"
: "=f" (__x), "=f" (__y), "=f" (__z), "=f" (__w)
: "0" (__x), "1" (__y), "2" (__z), "3" (__w)
);
oxyz[0] = __x;
oxyz[1] = __y;
oxyz[2] = __z;
*ow = __w;
}
static inline void TransformVertices(Vertex* vertices, const int count) {
Vertex* it = vertices;
for(int i = 0; i < count; ++i, ++it) {

View File

@ -3,12 +3,16 @@
#include <stdlib.h>
#include <string.h>
#include "../private.h"
#include "../platform.h"
#include "software.h"
#include "software/edge_equation.h"
#include "software/parameter_equation.h"
static size_t AVAILABLE_VRAM = 16 * 1024 * 1024;
#define CLIP_DEBUG 0
#define ZNEAR_CLIPPING_ENABLED 1
static size_t AVAILABLE_VRAM = 8 * 1024 * 1024;
static Matrix4x4 MATRIX;
static SDL_Window* WINDOW = NULL;
@ -23,98 +27,16 @@ static VideoMode vid_mode = {
640, 480
};
typedef struct GPUVertex {
uint32_t flags;
float x;
float y;
float z;
float u;
float v;
uint8_t bgra[4];
uint8_t obgra[4];
} GPUVertex;
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
static void DrawTriangle(GPUVertex* v0, GPUVertex* v1, GPUVertex* v2) {
// Compute triangle bounding box.
int minX = MIN(MIN(v0->x, v1->x), v2->x);
int maxX = MAX(MAX(v0->x, v1->x), v2->x);
int minY = MIN(MIN(v0->y, v1->y), v2->y);
int maxY = MAX(MAX(v0->y, v1->y), v2->y);
// Clip to scissor rect.
minX = MAX(minX, 0);
maxX = MIN(maxX, vid_mode.width);
minY = MAX(minY, 0);
maxY = MIN(maxY, vid_mode.height);
// Compute edge equations.
EdgeEquation e0, e1, e2;
EdgeEquationInit(&e0, &v0->x, &v1->x);
EdgeEquationInit(&e1, &v1->x, &v2->x);
EdgeEquationInit(&e2, &v2->x, &v0->x);
float area = 0.5 * (e0.c + e1.c + e2.c);
/* This is very ugly. I don't understand the math properly
* so I just swap the vertex order if something is back-facing
* and we want to render it. Patches welcome! */
#define REVERSE_WINDING() \
GPUVertex* tv = v0; \
v0 = v1; \
v1 = tv; \
EdgeEquationInit(&e0, &v0->x, &v1->x); \
EdgeEquationInit(&e1, &v1->x, &v2->x); \
EdgeEquationInit(&e2, &v2->x, &v0->x); \
area = 0.5f * (e0.c + e1.c + e2.c) \
// Check if triangle is backfacing.
if(CULL_MODE == GPU_CULLING_CCW) {
if(area < 0) {
return;
}
} else if(CULL_MODE == GPU_CULLING_CW) {
if(area < 0) {
// We only draw front-facing polygons, so swap
// the back to front and draw
REVERSE_WINDING();
} else {
// Front facing, so bail
return;
}
} else if(area < 0) {
/* We're not culling, but this is backfacing, so swap vertices and edges */
REVERSE_WINDING();
}
ParameterEquation r, g, b;
ParameterEquationInit(&r, v0->bgra[2], v1->bgra[2], v2->bgra[2], &e0, &e1, &e2, area);
ParameterEquationInit(&g, v0->bgra[1], v1->bgra[1], v2->bgra[1], &e0, &e1, &e2, area);
ParameterEquationInit(&b, v0->bgra[0], v1->bgra[0], v2->bgra[0], &e0, &e1, &e2, area);
// Add 0.5 to sample at pixel centers.
for (float x = minX + 0.5f, xm = maxX + 0.5f; x <= xm; x += 1.0f)
for (float y = minY + 0.5f, ym = maxY + 0.5f; y <= ym; y += 1.0f)
{
if (EdgeEquationTestPoint(&e0, x, y) && EdgeEquationTestPoint(&e1, x, y) && EdgeEquationTestPoint(&e2, x, y)) {
int rint = ParameterEquationEvaluate(&r, x, y);
int gint = ParameterEquationEvaluate(&g, x, y);
int bint = ParameterEquationEvaluate(&b, x, y);
SDL_SetRenderDrawColor(RENDERER, rint, gint, bint, 255);
SDL_RenderDrawPoint(RENDERER, x, y);
}
}
}
AlignedVector vbuffer;
void InitGPU(_Bool autosort, _Bool fsaa) {
// 32-bit SDL has trouble with the wayland driver for some reason
setenv("SDL_VIDEODRIVER", "x11", 1);
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
WINDOW = SDL_CreateWindow(
@ -128,6 +50,8 @@ void InitGPU(_Bool autosort, _Bool fsaa) {
RENDERER = SDL_CreateRenderer(
WINDOW, -1, SDL_RENDERER_ACCELERATED
);
aligned_vector_init(&vbuffer, sizeof(SDL_Vertex));
}
void SceneBegin() {
@ -135,18 +59,389 @@ void SceneBegin() {
SDL_RenderClear(RENDERER);
}
void SceneListBegin(GPUList list) {
static Vertex BUFFER[1024 * 32];
static uint32_t vertex_counter = 0;
GL_FORCE_INLINE bool glIsVertex(const float flags) {
return flags == GPU_CMD_VERTEX_EOL || flags == GPU_CMD_VERTEX;
}
void SceneListSubmit(void* src, int n) {
uint32_t vertex_counter = 0;
const uint32_t* flags = (const uint32_t*) src;
uint32_t step = sizeof(GPUVertex) / sizeof(uint32_t);
GL_FORCE_INLINE bool glIsLastVertex(const float flags) {
return flags == GPU_CMD_VERTEX_EOL;
}
for(int i = 0; i < n; ++i, flags += step) {
void SceneListBegin(GPUList list) {
vertex_counter = 0;
}
GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) {
const float f = 1.0f / (vertex->w);
/* Convert to NDC and apply viewport */
vertex->xyz[0] = __builtin_fmaf(
VIEWPORT.hwidth, vertex->xyz[0] * f, VIEWPORT.x_plus_hwidth
);
vertex->xyz[1] = h - __builtin_fmaf(
VIEWPORT.hheight, vertex->xyz[1] * f, VIEWPORT.y_plus_hheight
);
if(vertex->w == 1.0f) {
vertex->xyz[2] = 1.0f / (1.0001f + vertex->xyz[2]);
} else {
vertex->xyz[2] = f;
}
}
GL_FORCE_INLINE void _glPushHeaderOrVertex(const Vertex* v) {
#ifndef NDEBUG
if(glIsVertex(v->flags)) {
gl_assert(!isnan(v->xyz[2]));
gl_assert(!isnan(v->w));
}
#endif
#if CLIP_DEBUG
printf("Submitting: %x (%x)\n", v, v->flags);
#endif
BUFFER[vertex_counter++] = *v;
}
static inline void _glFlushBuffer() {}
GL_FORCE_INLINE void _glClipEdge(const Vertex* v1, const Vertex* v2, Vertex* vout) {
const static float o = 0.003921569f; // 1 / 255
const float d0 = v1->w + v1->xyz[2];
const float d1 = v2->w + v2->xyz[2];
const float t = (fabs(d0) * (1.0f / sqrtf((d1 - d0) * (d1 - d0)))) + 0.000001f;
const float invt = 1.0f - t;
vout->xyz[0] = invt * v1->xyz[0] + t * v2->xyz[0];
vout->xyz[1] = invt * v1->xyz[1] + t * v2->xyz[1];
vout->xyz[2] = invt * v1->xyz[2] + t * v2->xyz[2];
vout->uv[0] = invt * v1->uv[0] + t * v2->uv[0];
vout->uv[1] = invt * v1->uv[1] + t * v2->uv[1];
vout->w = invt * v1->w + t * v2->w;
const float m = 255 * t;
const float n = 255 - m;
vout->bgra[0] = (v1->bgra[0] * n + v2->bgra[0] * m) * o;
vout->bgra[1] = (v1->bgra[1] * n + v2->bgra[1] * m) * o;
vout->bgra[2] = (v1->bgra[2] * n + v2->bgra[2] * m) * o;
vout->bgra[3] = (v1->bgra[3] * n + v2->bgra[3] * m) * o;
}
void SceneListSubmit(Vertex* v2, int n) {
/* You need at least a header, and 3 vertices to render anything */
if(n < 4) {
return;
}
const float h = GetVideoMode()->height;
uint8_t visible_mask = 0;
uint8_t counter = 0;
for(int i = 0; i < n; ++i, ++v2) {
PREFETCH(v2 + 1);
switch(v2->flags) {
case GPU_CMD_VERTEX_EOL:
if(counter < 2) {
continue;
}
counter = 0;
break;
case GPU_CMD_VERTEX:
++counter;
if(counter < 3) {
continue;
}
break;
default:
_glPushHeaderOrVertex(v2);
counter = 0;
continue;
};
Vertex* const v0 = v2 - 2;
Vertex* const v1 = v2 - 1;
visible_mask = (
(v0->xyz[2] > -v0->w) << 0 |
(v1->xyz[2] > -v1->w) << 1 |
(v2->xyz[2] > -v2->w) << 2 |
(counter == 0) << 3
);
switch(visible_mask) {
case 15: /* All visible, but final vertex in strip */
{
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(v1, h);
_glPushHeaderOrVertex(v1);
_glPerspectiveDivideVertex(v2, h);
_glPushHeaderOrVertex(v2);
}
break;
case 7:
/* All visible, push the first vertex and move on */
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
break;
case 9:
/* First vertex was visible, last in strip */
{
Vertex __attribute__((aligned(32))) scratch[2];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v2, v0, b);
b->flags = GPU_CMD_VERTEX_EOL;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
}
break;
case 1:
/* First vertex was visible, but not last in strip */
{
Vertex __attribute__((aligned(32))) scratch[2];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v2, v0, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPushHeaderOrVertex(b);
}
break;
case 10:
case 2:
/* Second vertex was visible. In self case we need to create a triangle and produce
two new vertices: 1-2, and 2-3. */
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v1);
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v1, v2, b);
b->flags = v2->flags;
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
}
break;
case 11:
case 3: /* First and second vertex were visible */
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v1);
_glClipEdge(v2, v0, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glClipEdge(v1, v2, a);
a->flags = v2->flags;
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(c);
_glPushHeaderOrVertex(a);
}
break;
case 12:
case 4:
/* Third vertex was visible. */
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v2);
_glClipEdge(v2, v0, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v1, v2, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
if(counter % 2 == 1) {
_glPushHeaderOrVertex(a);
}
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
}
break;
case 13:
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v2);
c->flags = GPU_CMD_VERTEX;
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v1, v2, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
c->flags = GPU_CMD_VERTEX_EOL;
_glPushHeaderOrVertex(c);
}
break;
case 5: /* First and third vertex were visible */
{
Vertex __attribute__((aligned(32))) scratch[3];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
memcpy_vertex(c, v2);
c->flags = GPU_CMD_VERTEX;
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v1, v2, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(v0, h);
_glPushHeaderOrVertex(v0);
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPushHeaderOrVertex(c);
}
break;
case 14:
case 6: /* Second and third vertex were visible */
{
Vertex __attribute__((aligned(32))) scratch[4];
Vertex* a = &scratch[0];
Vertex* b = &scratch[1];
Vertex* c = &scratch[2];
Vertex* d = &scratch[3];
memcpy_vertex(c, v1);
memcpy_vertex(d, v2);
_glClipEdge(v0, v1, a);
a->flags = GPU_CMD_VERTEX;
_glClipEdge(v2, v0, b);
b->flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(a, h);
_glPushHeaderOrVertex(a);
_glPerspectiveDivideVertex(c, h);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(b, h);
_glPushHeaderOrVertex(b);
_glPushHeaderOrVertex(c);
_glPerspectiveDivideVertex(d, h);
_glPushHeaderOrVertex(d);
}
break;
case 8:
default:
break;
}
}
_glFlushBuffer();
}
void SceneListFinish() {
uint32_t vidx = 0;
const uint32_t* flags = (const uint32_t*) BUFFER;
uint32_t step = sizeof(Vertex) / sizeof(uint32_t);
for(int i = 0; i < vertex_counter; ++i, flags += step) {
if((*flags & GPU_CMD_POLYHDR) == GPU_CMD_POLYHDR) {
vertex_counter = 0;
vidx = 0;
uint32_t mode1 = *(flags + 1);
// Extract culling mode
@ -157,44 +452,62 @@ void SceneListSubmit(void* src, int n) {
switch(*flags) {
case GPU_CMD_VERTEX_EOL:
case GPU_CMD_VERTEX: // Fallthrough
vertex_counter++;
vidx++;
break;
default:
break;
}
}
if(vertex_counter > 2) {
GPUVertex* v0 = (GPUVertex*) (flags - step - step);
GPUVertex* v1 = (GPUVertex*) (flags - step);
GPUVertex* v2 = (GPUVertex*) (flags);
(vertex_counter % 2 == 0) ? DrawTriangle(v0, v1, v2) : DrawTriangle(v1, v0, v2);
if(vidx > 2) {
Vertex* v0 = (Vertex*) (flags - step - step);
Vertex* v1 = (Vertex*) (flags - step);
Vertex* v2 = (Vertex*) (flags);
SDL_Vertex sv0 = {
{v0->xyz[0], v0->xyz[1]},
{v0->bgra[2], v0->bgra[1], v0->bgra[0], v0->bgra[3]},
{v0->uv[0], v0->uv[1]}
};
SDL_Vertex sv1 = {
{v1->xyz[0], v1->xyz[1]},
{v1->bgra[2], v1->bgra[1], v1->bgra[0], v1->bgra[3]},
{v1->uv[0], v1->uv[1]}
};
SDL_Vertex sv2 = {
{v2->xyz[0], v2->xyz[1]},
{v2->bgra[2], v2->bgra[1], v2->bgra[0], v2->bgra[3]},
{v2->uv[0], v2->uv[1]}
};
aligned_vector_push_back(&vbuffer, &sv0, 1);
aligned_vector_push_back(&vbuffer, &sv1, 1);
aligned_vector_push_back(&vbuffer, &sv2, 1);
}
if((*flags) == GPU_CMD_VERTEX_EOL) {
vertex_counter = 0;
vidx = 0;
}
}
}
void SceneListFinish() {
SDL_SetRenderDrawColor(RENDERER, 255, 255, 255, 255);
SDL_RenderGeometry(RENDERER, NULL, aligned_vector_front(&vbuffer), aligned_vector_size(&vbuffer), NULL, 0);
}
void SceneFinish() {
SDL_RenderPresent(RENDERER);
/* Only sensible place to hook the quit signal */
SDL_Event e = {0};
while (SDL_PollEvent(&e))
switch (e.type) {
case SDL_QUIT:
exit(0);
break;
default:
break;
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_QUIT:
exit(0);
break;
default:
break;
}
}
}
@ -328,3 +641,18 @@ void TransformVertices(Vertex* vertices, const int count) {
vertices->w = ret[3];
}
}
void TransformVertex(const float* xyz, const float* w, float* oxyz, float* ow) {
float ret[4];
ret[0] = xyz[0];
ret[1] = xyz[1];
ret[2] = xyz[2];
ret[3] = *w;
TransformVec4(ret);
oxyz[0] = ret[0];
oxyz[1] = ret[1];
oxyz[2] = ret[2];
*ow = ret[3];
}

View File

@ -5,6 +5,8 @@
#include "../types.h"
#define PREFETCH(addr) do {} while(0)
#define MATH_Fast_Divide(n, d) (n / d)
#define MATH_fmac(a, b, c) (a * b + c)
#define MATH_Fast_Sqrt(x) sqrtf((x))
@ -12,7 +14,9 @@
#define MATH_Fast_Invert(x) (1.0f / (x))
#define FASTCPY(dst, src, bytes) memcpy(dst, src, bytes)
#define FASTCPY4(dst, src, bytes) memcpy(dst, src, bytes)
#define MEMCPY(dst, src, bytes) memcpy(dst, src, bytes)
#define MEMCPY4(dst, src, bytes) memcpy(dst, src, bytes)
#define MEMSET4(dst, v, size) memset((dst), (v), (size))
#define VEC3_NORMALIZE(x, y, z) \
@ -44,10 +48,12 @@ void TransformVec3NoMod(const float* v, float* ret);
/* Transform a 3-element normal using the stored matrix (w == 0)*/
static inline void TransformNormalNoMod(const float* xIn, float* xOut) {
(void) xIn;
(void) xOut;
}
void TransformVertices(Vertex* vertices, const int count);
void TransformVertex(const float* xyz, const float* w, float* oxyz, float* ow);
void InitGPU(_Bool autosort, _Bool fsaa);

View File

@ -4,6 +4,7 @@
#include <stdint.h>
#include <stdio.h>
#include "gl_assert.h"
#include "platform.h"
#include "types.h"
@ -14,6 +15,11 @@
#include "../containers/aligned_vector.h"
#include "../containers/named_array.h"
#define MAX_GLDC_4BPP_PALETTE_SLOTS 16
#define MAX_GLDC_PALETTE_SLOTS 4
#define MAX_GLDC_SHARED_PALETTES (MAX_GLDC_PALETTE_SLOTS*MAX_GLDC_4BPP_PALETTE_SLOTS)
extern void* memcpy4 (void *dest, const void *src, size_t count);
#define GL_NO_INSTRUMENT inline __attribute__((no_instrument_function))
@ -98,6 +104,20 @@ typedef struct {
AlignedVector vector;
} PolyList;
typedef struct {
GLint x;
GLint y;
GLint width;
GLint height;
float x_plus_hwidth;
float y_plus_hheight;
float hwidth; /* width * 0.5f */
float hheight; /* height * 0.5f */
} Viewport;
extern Viewport VIEWPORT;
typedef struct {
/* Palette data is always stored in RAM as RGBA8888 and packed as ARGB8888
* when uploaded to the PVR */
@ -144,7 +164,10 @@ typedef struct {
GLboolean isCompressed;
GLboolean isPaletted;
//50
} TextureObject;
GLenum internalFormat;
//54
GLubyte padding[10]; // Pad to 64-bytes
} __attribute__((aligned(32))) TextureObject;
typedef struct {
GLfloat emissive[4];
@ -185,7 +208,7 @@ typedef struct {
#define argbcpy(dst, src) \
*((GLuint*) dst) = *((GLuint*) src) \
*((GLuint*) dst) = *((const GLuint*) src) \
typedef struct {
@ -213,11 +236,41 @@ GL_FORCE_INLINE float clamp(float d, float min, float max) {
return (d < min) ? min : (d > max) ? max : d;
}
GL_FORCE_INLINE void memcpy_vertex(Vertex *dest, const Vertex *src) {
#ifdef __DREAMCAST__
_Complex float double_scratch;
asm volatile (
"fschg\n\t"
"clrs\n\t"
".align 2\n\t"
"fmov.d @%[in]+, %[scratch]\n\t"
"fmov.d %[scratch], @%[out]\n\t"
"fmov.d @%[in]+, %[scratch]\n\t"
"add #8, %[out]\n\t"
"fmov.d %[scratch], @%[out]\n\t"
"fmov.d @%[in]+, %[scratch]\n\t"
"add #8, %[out]\n\t"
"fmov.d %[scratch], @%[out]\n\t"
"fmov.d @%[in], %[scratch]\n\t"
"add #8, %[out]\n\t"
"fmov.d %[scratch], @%[out]\n\t"
"fschg\n"
: [in] "+&r" ((uint32_t) src), [scratch] "=&d" (double_scratch), [out] "+&r" ((uint32_t) dest)
:
: "t", "memory" // clobbers
);
#else
*dest = *src;
#endif
}
#define swapVertex(a, b) \
do { \
Vertex c = *a; \
*a = *b; \
*b = c; \
Vertex __attribute__((aligned(32))) c; \
memcpy_vertex(&c, a); \
memcpy_vertex(a, b); \
memcpy_vertex(b, &c); \
} while(0)
/* ClipVertex doesn't have room for these, so we need to parse them
@ -231,7 +284,7 @@ typedef struct {
* when a realloc could invalidate pointers. This structure holds all the information
* we need on the target vertex array to allow passing around to the various stages (e.g. generate/clip etc.)
*/
typedef struct {
typedef struct __attribute__((aligned(32))) {
PolyList* output;
uint32_t header_offset; // The offset of the header in the output list
uint32_t start_offset; // The offset into the output list
@ -241,7 +294,6 @@ typedef struct {
AlignedVector* extras;
} SubmissionTarget;
PolyHeader* _glSubmissionTargetHeader(SubmissionTarget* target);
Vertex* _glSubmissionTargetStart(SubmissionTarget* target);
Vertex* _glSubmissionTargetEnd(SubmissionTarget* target);
@ -261,10 +313,6 @@ typedef enum {
struct SubmissionTarget;
float _glClipLineToNearZ(const Vertex* v1, const Vertex* v2, Vertex* vout);
void _glClipTriangleStrip(SubmissionTarget* target, uint8_t fladeShade);
PolyList *_glActivePolyList();
PolyList* _glOpaquePolyList();
PolyList* _glPunchThruPolyList();
PolyList *_glTransparentPolyList();
@ -275,11 +323,13 @@ void _glInitLights();
void _glInitImmediateMode(GLuint initial_size);
void _glInitMatrices();
void _glInitFramebuffers();
void _glInitSubmissionTarget();
void _glMatrixLoadNormal();
void _glMatrixLoadModelView();
void _glMatrixLoadProjection();
void _glMatrixLoadTexture();
void _glApplyRenderMatrix();
void _glMatrixLoadModelViewProjection();
extern GLfloat DEPTH_RANGE_MULTIPLIER_L;
extern GLfloat DEPTH_RANGE_MULTIPLIER_H;
@ -288,21 +338,28 @@ Matrix4x4* _glGetProjectionMatrix();
Matrix4x4* _glGetModelViewMatrix();
void _glWipeTextureOnFramebuffers(GLuint texture);
GLubyte _glCheckImmediateModeInactive(const char* func);
PolyContext* _glGetPVRContext();
GLubyte _glInitTextures();
void _glUpdatePVRTextureContext(PolyContext* context, GLshort textureUnit);
void _glAllocateSpaceForMipmaps(TextureObject* active);
typedef struct {
const void* ptr;
GLenum type;
GLsizei stride;
GLint size;
const void* ptr; // 4
GLenum type; // 4
GLsizei stride; // 4
GLint size; // 4
} AttribPointer;
typedef struct {
AttribPointer vertex; // 16
AttribPointer colour; // 32
AttribPointer uv; // 48
AttribPointer st; // 64
AttribPointer normal; // 80
AttribPointer padding; // 96
} AttribPointerList;
GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func);
GLuint* _glGetEnabledAttributes();
@ -316,7 +373,15 @@ GLenum _glGetShadeModel();
TextureObject* _glGetTexture0();
TextureObject* _glGetTexture1();
TextureObject* _glGetBoundTexture();
extern GLubyte ACTIVE_TEXTURE;
extern GLboolean TEXTURES_ENABLED[];
GLubyte _glGetActiveTexture();
GLint _glGetTextureInternalFormat();
GLboolean _glGetTextureTwiddle();
void _glSetTextureTwiddle(GLboolean v);
GLuint _glGetActiveClientTexture();
TexturePalette* _glGetSharedPalette(GLshort bank);
void _glSetInternalPaletteFormat(GLenum val);
@ -326,23 +391,148 @@ void _glApplyColorTable(TexturePalette *palette);
GLboolean _glIsBlendingEnabled();
GLboolean _glIsAlphaTestEnabled();
GLboolean _glIsCullingEnabled();
GLboolean _glIsDepthTestEnabled();
GLboolean _glIsDepthWriteEnabled();
GLboolean _glIsScissorTestEnabled();
GLboolean _glIsFogEnabled();
GLenum _glGetDepthFunc();
GLenum _glGetCullFace();
GLenum _glGetFrontFace();
GLenum _glGetBlendSourceFactor();
GLenum _glGetBlendDestFactor();
extern PolyList OP_LIST;
extern PolyList PT_LIST;
extern PolyList TR_LIST;
GL_FORCE_INLINE PolyList* _glActivePolyList() {
if(_glIsBlendingEnabled()) {
return &TR_LIST;
} else if(_glIsAlphaTestEnabled()) {
return &PT_LIST;
} else {
return &OP_LIST;
}
}
GLboolean _glIsMipmapComplete(const TextureObject* obj);
GLubyte* _glGetMipmapLocation(const TextureObject* obj, GLuint level);
GLuint _glGetMipmapLevelCount(const TextureObject* obj);
GLboolean _glIsLightingEnabled();
void _glEnableLight(GLubyte light, unsigned char value);
void _glEnableLight(GLubyte light, GLboolean value);
GLboolean _glIsColorMaterialEnabled();
GLboolean _glIsNormalizeEnabled();
GLboolean _glRecalcFastPath();
extern AttribPointerList ATTRIB_POINTERS;
extern GLuint ENABLED_VERTEX_ATTRIBUTES;
extern GLuint FAST_PATH_ENABLED;
GL_FORCE_INLINE GLuint _glIsVertexDataFastPathCompatible() {
/* The fast path is enabled when all enabled elements of the vertex
* match the output format. This means:
*
* xyz == 3f
* uv == 2f
* rgba == argb4444
* st == 2f
* normal == 3f
*
* When this happens we do inline straight copies of the enabled data
* and transforms for positions and normals happen while copying.
*/
if((ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) {
if(ATTRIB_POINTERS.vertex.size != 3 || ATTRIB_POINTERS.vertex.type != GL_FLOAT) {
return GL_FALSE;
}
}
if((ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG)) {
if(ATTRIB_POINTERS.uv.size != 2 || ATTRIB_POINTERS.uv.type != GL_FLOAT) {
return GL_FALSE;
}
}
if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG)) {
/* FIXME: Shouldn't this be a reversed format? */
if(ATTRIB_POINTERS.colour.size != GL_BGRA || ATTRIB_POINTERS.colour.type != GL_UNSIGNED_BYTE) {
return GL_FALSE;
}
}
if((ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG)) {
if(ATTRIB_POINTERS.st.size != 2 || ATTRIB_POINTERS.st.type != GL_FLOAT) {
return GL_FALSE;
}
}
if((ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG)) {
if(ATTRIB_POINTERS.normal.size != 3 || ATTRIB_POINTERS.normal.type != GL_FLOAT) {
return GL_FALSE;
}
}
return GL_TRUE;
}
GL_FORCE_INLINE GLuint _glRecalcFastPath() {
FAST_PATH_ENABLED = _glIsVertexDataFastPathCompatible();
return FAST_PATH_ENABLED;
}
extern GLboolean IMMEDIATE_MODE_ACTIVE;
extern GLenum LAST_ERROR;
extern char ERROR_FUNCTION[64];
GL_FORCE_INLINE const char* _glErrorEnumAsString(GLenum error) {
switch(error) {
case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
default:
return "GL_UNKNOWN_ERROR";
}
}
GL_FORCE_INLINE void _glKosThrowError(GLenum error, const char *function) {
if(LAST_ERROR == GL_NO_ERROR) {
LAST_ERROR = error;
sprintf(ERROR_FUNCTION, "%s\n", function);
fprintf(stderr, "GL ERROR: %s when calling %s\n", _glErrorEnumAsString(LAST_ERROR), ERROR_FUNCTION);
}
}
GL_FORCE_INLINE GLubyte _glKosHasError() {
return (LAST_ERROR != GL_NO_ERROR) ? GL_TRUE : GL_FALSE;
}
GL_FORCE_INLINE void _glKosResetError() {
LAST_ERROR = GL_NO_ERROR;
sprintf(ERROR_FUNCTION, "\n");
}
GL_FORCE_INLINE GLboolean _glCheckImmediateModeInactive(const char* func) {
/* Returns 1 on error */
if(IMMEDIATE_MODE_ACTIVE) {
_glKosThrowError(GL_INVALID_OPERATION, func);
return GL_TRUE;
}
return GL_FALSE;
}
typedef struct {
float xyz[3]; // 12 bytes
float n[3]; // 12 bytes
float finalColour[4]; //16 bytes (to 40)
float finalColour[4]; //28 bytes
uint32_t padding; // 32 bytes
} EyeSpaceData;
extern void _glPerformLighting(Vertex* vertices, EyeSpaceData *es, const uint32_t count);
@ -350,18 +540,42 @@ extern void _glPerformLighting(Vertex* vertices, EyeSpaceData *es, const uint32_
unsigned char _glIsClippingEnabled();
void _glEnableClipping(unsigned char v);
void _glKosThrowError(GLenum error, const char *function);
void _glKosPrintError();
GLubyte _glKosHasError();
GLuint _glFreeTextureMemory();
GLuint _glUsedTextureMemory();
GLuint _glFreeContiguousTextureMemory();
void _glApplyScissor(bool force);
void _glSetColorMaterialMask(GLenum mask);
void _glSetColorMaterialMode(GLenum mode);
GLenum _glColorMaterialMode();
#define MAX_TEXTURE_UNITS 2
#define MAX_LIGHTS 8
Material* _glActiveMaterial();
void _glSetLightModelViewerInEyeCoordinates(GLboolean v);
void _glSetLightModelSceneAmbient(const GLfloat* v);
void _glSetLightModelColorControl(GLint v);
GLuint _glEnabledLightCount();
void _glRecalcEnabledLights();
GLfloat* _glLightModelSceneAmbient();
GLfloat* _glGetLightModelSceneAmbient();
LightSource* _glLightAt(GLuint i);
GLboolean _glNearZClippingEnabled();
GLboolean _glGPUStateIsDirty();
void _glGPUStateMarkClean();
void _glGPUStateMarkDirty();
#define MAX_GLDC_TEXTURE_UNITS 2
#define MAX_GLDC_LIGHTS 8
#define AMBIENT_MASK 1
#define DIFFUSE_MASK 2
#define EMISSION_MASK 4
#define SPECULAR_MASK 8
#define SCENE_AMBIENT_MASK 16
/* This is from KOS pvr_buffers.c */
#define PVR_MIN_Z 0.0001f
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

View File

@ -1,145 +0,0 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "profiler.h"
#include "../containers/aligned_vector.h"
#if PROFILING_COMPILED
#define MAX_PATH 256
typedef struct {
char name[MAX_PATH];
uint64_t total_time_us;
uint64_t total_calls;
} ProfilerResult;
typedef struct {
AlignedVector stack;
AlignedVector results;
uint64_t start_time_in_us;
} RootProfiler;
static RootProfiler* root = NULL;
static char PROFILER_ENABLED = 0;
void profiler_enable() {
PROFILER_ENABLED = 1;
}
void profiler_disable() {
PROFILER_ENABLED = 0;
}
static ProfilerResult* profiler_get_or_create_result(const char* name) {
if(!PROFILER_ENABLED) return NULL;
uint16_t i = 0;
for(; i < root->results.size; ++i) {
ProfilerResult* result = aligned_vector_at(&root->results, i);
if(strcmp(result->name, name) == 0) {
return result;
}
}
ProfilerResult newResult;
strcpy(newResult.name, name);
newResult.total_calls = 0;
newResult.total_time_us = 0;
aligned_vector_push_back(&root->results, &newResult, 1);
return aligned_vector_back(&root->results);
}
static uint64_t current_time_in_us() {
return timer_us_gettime64();
}
static void profiler_generate_path(const char* suffix, char* path) {
uint16_t i = 0;
for(; i < root->stack.size; ++i) {
Profiler* prof = aligned_vector_at(&root->stack, i);
strcat(path, prof->name);
if(i != root->stack.size - 1) {
strcat(path, ".");
}
}
if(strlen(suffix)) {
strcat(path, ":");
strcat(path, suffix);
}
}
Profiler* profiler_push(const char* name) {
if(!PROFILER_ENABLED) return NULL;
if(!root) {
root = (RootProfiler*) malloc(sizeof(RootProfiler));
aligned_vector_init(
&root->stack,
sizeof(Profiler)
);
aligned_vector_init(
&root->results,
sizeof(ProfilerResult)
);
aligned_vector_reserve(&root->stack, 32);
aligned_vector_reserve(&root->results, 64);
}
Profiler profiler;
strncpy(profiler.name, name, 64);
profiler.start_time_in_us = current_time_in_us();
aligned_vector_push_back(&root->stack, &profiler, 1);
return aligned_vector_back(&root->stack);
}
void profiler_checkpoint(const char* name) {
if(!PROFILER_ENABLED) return;
Profiler* prof = aligned_vector_back(&root->stack);
char path[MAX_PATH];
path[0] = '\0';
profiler_generate_path(name, path);
uint64_t now = current_time_in_us();
uint64_t diff = now - prof->start_time_in_us;
prof->start_time_in_us = now;
ProfilerResult* result = profiler_get_or_create_result(path);
result->total_calls++;
result->total_time_us += diff;
}
void profiler_pop() {
if(!PROFILER_ENABLED) return;
aligned_vector_resize(&root->stack, root->stack.size - 1);
}
void profiler_print_stats() {
if(!PROFILER_ENABLED) return;
fprintf(stderr, "%-60s%-20s%-20s%-20s\n", "Path", "Average", "Total", "Calls");
uint16_t i = 0;
for(; i < root->results.size; ++i) {
ProfilerResult* result = aligned_vector_at(&root->results, i);
float ms = ((float) result->total_time_us) / 1000.0f;
float avg = ms / (float) result->total_calls;
fprintf(stderr, "%-60s%-20f%-20f%" PRIu64 "\n", result->name, (double)avg, (double)ms, result->total_calls);
}
}
#endif

View File

@ -1,32 +0,0 @@
#pragma once
#include <stdint.h>
typedef struct {
char name[64];
uint64_t start_time_in_us;
} Profiler;
#define PROFILING_COMPILED 0
#if PROFILING_COMPILED
Profiler* profiler_push(const char* name);
void _profiler_checkpoint(const char* name);
void _profiler_pop();
void _profiler_print_stats();
void _profiler_enable();
void _profiler_disable();
#else
#define profiler_push(name);
#define profiler_checkpoint(name);
#define profiler_pop();
#define profiler_print_stats();
#define profiler_enable();
#define profiler_disable();
#endif

View File

@ -4,142 +4,228 @@
#include "private.h"
static PolyContext GL_CONTEXT;
PolyContext *_glGetPVRContext() {
return &GL_CONTEXT;
}
static struct {
GLboolean is_dirty;
/* We can't just use the GL_CONTEXT for this state as the two
* GL states are combined, so we store them separately and then
* calculate the appropriate PVR state from them. */
static GLenum CULL_FACE = GL_BACK;
static GLenum FRONT_FACE = GL_CCW;
static GLboolean CULLING_ENABLED = GL_FALSE;
static GLboolean COLOR_MATERIAL_ENABLED = GL_FALSE;
GLenum depth_func;
GLboolean depth_test_enabled;
GLenum cull_face;
GLenum front_face;
GLboolean culling_enabled;
GLboolean color_material_enabled;
GLboolean znear_clipping_enabled;
GLboolean lighting_enabled;
GLboolean shared_palette_enabled;
GLboolean alpha_test_enabled;
GLboolean polygon_offset_enabled;
GLboolean normalize_enabled;
GLboolean scissor_test_enabled;
GLboolean fog_enabled;
GLboolean depth_mask_enabled;
static GLboolean LIGHTING_ENABLED = GL_FALSE;
struct {
GLint x;
GLint y;
GLsizei width;
GLsizei height;
GLboolean applied;
} scissor_rect;
/* Is the shared texture palette enabled? */
static GLboolean SHARED_PALETTE_ENABLED = GL_FALSE;
GLenum blend_sfactor;
GLenum blend_dfactor;
GLboolean blend_enabled;
GLfloat offset_factor;
GLfloat offset_units;
static GLboolean ALPHA_TEST_ENABLED = GL_FALSE;
GLfloat scene_ambient[4];
GLboolean viewer_in_eye_coords;
GLenum color_control;
GLenum color_material_mode;
GLenum color_material_mask;
static GLboolean POLYGON_OFFSET_ENABLED = GL_FALSE;
LightSource lights[MAX_GLDC_LIGHTS];
GLuint enabled_light_count;
Material material;
static GLboolean NORMALIZE_ENABLED = GL_FALSE;
static struct {
GLint x;
GLint y;
GLsizei width;
GLsizei height;
GLboolean applied;
} SCISSOR_RECT = {
0, 0, 640, 480, false
GLenum shade_model;
} GPUState = {
.is_dirty = GL_TRUE,
.depth_func = GL_LESS,
.depth_test_enabled = GL_FALSE,
.cull_face = GL_BACK,
.front_face = GL_CCW,
.culling_enabled = GL_FALSE,
.color_material_enabled = GL_FALSE,
.znear_clipping_enabled = GL_TRUE,
.lighting_enabled = GL_FALSE,
.shared_palette_enabled = GL_FALSE,
.alpha_test_enabled = GL_FALSE,
.polygon_offset_enabled = GL_FALSE,
.normalize_enabled = GL_FALSE,
.scissor_test_enabled = GL_FALSE,
.fog_enabled = GL_FALSE,
.depth_mask_enabled = GL_FALSE,
.scissor_rect = {0, 0, 640, 480, false},
.blend_sfactor = GL_ONE,
.blend_dfactor = GL_ZERO,
.blend_enabled = GL_FALSE,
.offset_factor = 0.0f,
.offset_units = 0.0f,
.scene_ambient = {0.2f, 0.2f, 0.2f, 1.0f},
.viewer_in_eye_coords = GL_TRUE,
.color_control = GL_SINGLE_COLOR,
.color_material_mode = GL_AMBIENT_AND_DIFFUSE,
.color_material_mask = AMBIENT_MASK | DIFFUSE_MASK,
.lights = {0},
.enabled_light_count = 0,
.material = {0},
.shade_model = GL_SMOOTH
};
GLboolean _glIsSharedTexturePaletteEnabled() {
return SHARED_PALETTE_ENABLED;
void _glGPUStateMarkClean() {
GPUState.is_dirty = GL_FALSE;
}
void _glApplyScissor(bool force);
void _glGPUStateMarkDirty() {
GPUState.is_dirty = GL_TRUE;
}
static int _calc_pvr_face_culling() {
if(!CULLING_ENABLED) {
return GPU_CULLING_NONE;
} else {
if(CULL_FACE == GL_BACK) {
return (FRONT_FACE == GL_CW) ? GPU_CULLING_CCW : GPU_CULLING_CW;
} else {
return (FRONT_FACE == GL_CCW) ? GPU_CULLING_CCW : GPU_CULLING_CW;
GLboolean _glGPUStateIsDirty() {
return GPUState.is_dirty;
}
Material* _glActiveMaterial() {
return &GPUState.material;
}
LightSource* _glLightAt(GLuint i) {
assert(i < MAX_GLDC_LIGHTS);
return &GPUState.lights[i];
}
void _glEnableLight(GLubyte light, GLboolean value) {
GPUState.lights[light].isEnabled = value;
}
GLboolean _glIsDepthTestEnabled() {
return GPUState.depth_test_enabled;
}
GLenum _glGetDepthFunc() {
return GPUState.depth_func;
}
GLboolean _glIsDepthWriteEnabled() {
return GPUState.depth_mask_enabled;
}
GLenum _glGetShadeModel() {
return GPUState.shade_model;
}
GLuint _glEnabledLightCount() {
return GPUState.enabled_light_count;
}
GLfloat* _glLightModelSceneAmbient() {
return GPUState.scene_ambient;
}
GLboolean _glIsBlendingEnabled() {
return GPUState.blend_enabled;
}
GLboolean _glIsAlphaTestEnabled() {
return GPUState.alpha_test_enabled;
}
GLboolean _glIsCullingEnabled() {
return GPUState.culling_enabled;
}
GLenum _glGetCullFace() {
return GPUState.cull_face;
}
GLenum _glGetFrontFace() {
return GPUState.front_face;
}
GLboolean _glIsFogEnabled() {
return GPUState.fog_enabled;
}
GLboolean _glIsScissorTestEnabled() {
return GPUState.scissor_test_enabled;
}
void _glRecalcEnabledLights() {
GPUState.enabled_light_count = 0;
for(GLubyte i = 0; i < MAX_GLDC_LIGHTS; ++i) {
if(_glLightAt(i)->isEnabled) {
GPUState.enabled_light_count++;
}
}
}
static GLenum DEPTH_FUNC = GL_LESS;
static GLboolean DEPTH_TEST_ENABLED = GL_FALSE;
static int _calc_pvr_depth_test() {
if(!DEPTH_TEST_ENABLED) {
return GPU_DEPTHCMP_ALWAYS;
}
switch(DEPTH_FUNC) {
case GL_NEVER:
return GPU_DEPTHCMP_NEVER;
case GL_LESS:
return GPU_DEPTHCMP_GREATER;
case GL_EQUAL:
return GPU_DEPTHCMP_EQUAL;
case GL_LEQUAL:
return GPU_DEPTHCMP_GEQUAL;
case GL_GREATER:
return GPU_DEPTHCMP_LESS;
case GL_NOTEQUAL:
return GPU_DEPTHCMP_NOTEQUAL;
case GL_GEQUAL:
return GPU_DEPTHCMP_LEQUAL;
break;
case GL_ALWAYS:
default:
return GPU_DEPTHCMP_ALWAYS;
}
void _glSetLightModelViewerInEyeCoordinates(GLboolean v) {
GPUState.viewer_in_eye_coords = v;
}
static GLenum BLEND_SFACTOR = GL_ONE;
static GLenum BLEND_DFACTOR = GL_ZERO;
static GLboolean BLEND_ENABLED = GL_FALSE;
void _glSetLightModelSceneAmbient(const GLfloat* v) {
vec4cpy(GPUState.scene_ambient, v);
}
static GLfloat OFFSET_FACTOR = 0.0f;
static GLfloat OFFSET_UNITS = 0.0f;
GLfloat* _glGetLightModelSceneAmbient() {
return GPUState.scene_ambient;
}
void _glSetLightModelColorControl(GLint v) {
GPUState.color_control = v;
}
GLenum _glColorMaterialMask() {
return GPUState.color_material_mask;
}
void _glSetColorMaterialMask(GLenum mask) {
GPUState.color_material_mask = mask;
}
void _glSetColorMaterialMode(GLenum mode) {
GPUState.color_material_mode = mode;
}
GLenum _glColorMaterialMode() {
return GPUState.color_material_mode;
}
GLboolean _glIsSharedTexturePaletteEnabled() {
return GPUState.shared_palette_enabled;
}
GLboolean _glNearZClippingEnabled() {
return GPUState.znear_clipping_enabled;
}
void _glApplyScissor(bool force);
GLboolean _glIsNormalizeEnabled() {
return NORMALIZE_ENABLED;
return GPUState.normalize_enabled;
}
GLboolean _glIsBlendingEnabled() {
return BLEND_ENABLED;
GLenum _glGetBlendSourceFactor() {
return GPUState.blend_sfactor;
}
GLboolean _glIsAlphaTestEnabled() {
return ALPHA_TEST_ENABLED;
GLenum _glGetBlendDestFactor() {
return GPUState.blend_dfactor;
}
static int _calcPVRBlendFactor(GLenum factor) {
switch(factor) {
case GL_ZERO:
return GPU_BLEND_ZERO;
case GL_SRC_ALPHA:
return GPU_BLEND_SRCALPHA;
case GL_DST_COLOR:
return GPU_BLEND_DESTCOLOR;
case GL_DST_ALPHA:
return GPU_BLEND_DESTALPHA;
case GL_ONE_MINUS_DST_COLOR:
return GPU_BLEND_INVDESTCOLOR;
case GL_ONE_MINUS_SRC_ALPHA:
return GPU_BLEND_INVSRCALPHA;
case GL_ONE_MINUS_DST_ALPHA:
return GPU_BLEND_INVDESTALPHA;
case GL_ONE:
return GPU_BLEND_ONE;
default:
fprintf(stderr, "Invalid blend mode: %u\n", (unsigned int) factor);
return GPU_BLEND_ONE;
}
}
static void _updatePVRBlend(PolyContext* context) {
if(BLEND_ENABLED || ALPHA_TEST_ENABLED) {
context->gen.alpha = GPU_ALPHA_ENABLE;
} else {
context->gen.alpha = GPU_ALPHA_DISABLE;
}
context->blend.src = _calcPVRBlendFactor(BLEND_SFACTOR);
context->blend.dst = _calcPVRBlendFactor(BLEND_DFACTOR);
}
GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func) {
GLubyte found = 0;
@ -153,7 +239,6 @@ GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func) {
if(!found) {
_glKosThrowError(GL_INVALID_ENUM, func);
_glKosPrintError();
return GL_TRUE;
}
@ -170,11 +255,12 @@ void _glUpdatePVRTextureContext(PolyContext *context, GLshort textureUnit) {
context->txr2.enable = GPU_TEXTURE_DISABLE;
context->txr2.alpha = GPU_TXRALPHA_DISABLE;
if(!TEXTURES_ENABLED[textureUnit] || !tx1) {
if(!TEXTURES_ENABLED[textureUnit] || !tx1 || !tx1->data) {
context->txr.base = NULL;
return;
}
context->txr.alpha = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? GPU_TXRALPHA_ENABLE : GPU_TXRALPHA_DISABLE;
context->txr.alpha = (GPUState.blend_enabled || GPUState.alpha_test_enabled) ? GPU_TXRALPHA_ENABLE : GPU_TXRALPHA_DISABLE;
GLuint filter = GPU_FILTER_NEAREST;
GLboolean enableMipmaps = GL_FALSE;
@ -202,11 +288,13 @@ void _glUpdatePVRTextureContext(PolyContext *context, GLshort textureUnit) {
}
if(enableMipmaps) {
if(tx1->minFilter == GL_LINEAR_MIPMAP_NEAREST) {
// FIXME: This is probably the wrong filter for this
// GL mode, but I'm not sure what's correct...
if(tx1->minFilter == GL_NEAREST_MIPMAP_LINEAR) {
filter = GPU_FILTER_TRILINEAR1;
} else if(tx1->minFilter == GL_LINEAR_MIPMAP_LINEAR) {
filter = GPU_FILTER_TRILINEAR2;
} else if(tx1->minFilter == GL_NEAREST_MIPMAP_LINEAR) {
} else if(tx1->minFilter == GL_LINEAR_MIPMAP_NEAREST) {
filter = GPU_FILTER_BILINEAR;
} else {
filter = GPU_FILTER_NEAREST;
@ -243,9 +331,20 @@ void _glUpdatePVRTextureContext(PolyContext *context, GLshort textureUnit) {
if(tx1->isPaletted) {
if(_glIsSharedTexturePaletteEnabled()) {
TexturePalette* palette = _glGetSharedPalette(tx1->shared_bank);
context->txr.format |= GPUPaletteSelect8BPP(palette->bank);
} else {
context->txr.format |= GPUPaletteSelect8BPP((tx1->palette) ? tx1->palette->bank : 0);
if (palette->size != 16){
context->txr.format |= GPUPaletteSelect8BPP(palette->bank);
}
else{
context->txr.format |= GPUPaletteSelect4BPP(palette->bank);
}
}
else {
if (tx1->palette->size != 16){
context->txr.format |= GPUPaletteSelect8BPP((tx1->palette) ? tx1->palette->bank : 0);
}
else{
context->txr.format |= GPUPaletteSelect4BPP((tx1->palette) ? tx1->palette->bank : 0);
}
}
}
@ -256,33 +355,27 @@ void _glUpdatePVRTextureContext(PolyContext *context, GLshort textureUnit) {
}
GLboolean _glIsLightingEnabled() {
return LIGHTING_ENABLED;
return GPUState.lighting_enabled;
}
GLboolean _glIsColorMaterialEnabled() {
return COLOR_MATERIAL_ENABLED;
return GPUState.color_material_enabled;
}
static GLfloat CLEAR_COLOUR[3];
void _glInitContext() {
memset(&GL_CONTEXT, 0, sizeof(PolyContext));
GL_CONTEXT.list_type = GPU_LIST_OP_POLY;
GL_CONTEXT.fmt.color = GPU_CLRFMT_ARGBPACKED;
GL_CONTEXT.fmt.uv = GPU_UVFMT_32BIT;
GL_CONTEXT.gen.color_clamp = GPU_CLRCLAMP_DISABLE;
const VideoMode* mode = GetVideoMode();
SCISSOR_RECT.x = 0;
SCISSOR_RECT.y = 0;
SCISSOR_RECT.width = mode->width;
SCISSOR_RECT.height = mode->height;
GPUState.scissor_rect.x = 0;
GPUState.scissor_rect.y = 0;
GPUState.scissor_rect.width = mode->width;
GPUState.scissor_rect.height = mode->height;
glClearDepth(1.0f);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
glShadeModel(GL_SMOOTH);
@ -297,7 +390,7 @@ void _glInitContext() {
glDisable(GL_LIGHTING);
GLubyte i;
for(i = 0; i < MAX_LIGHTS; ++i) {
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
glDisable(GL_LIGHT0 + i);
}
}
@ -305,40 +398,66 @@ void _glInitContext() {
GLAPI void APIENTRY glEnable(GLenum cap) {
switch(cap) {
case GL_TEXTURE_2D:
TEXTURES_ENABLED[_glGetActiveTexture()] = GL_TRUE;
if(TEXTURES_ENABLED[_glGetActiveTexture()] != GL_TRUE) {
TEXTURES_ENABLED[_glGetActiveTexture()] = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_CULL_FACE: {
CULLING_ENABLED = GL_TRUE;
GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
if(GPUState.culling_enabled != GL_TRUE) {
GPUState.culling_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_DEPTH_TEST: {
DEPTH_TEST_ENABLED = GL_TRUE;
GL_CONTEXT.depth.comparison = _calc_pvr_depth_test();
if(GPUState.depth_test_enabled != GL_TRUE) {
GPUState.depth_test_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_BLEND: {
BLEND_ENABLED = GL_TRUE;
_updatePVRBlend(&GL_CONTEXT);
if(GPUState.blend_enabled != GL_TRUE) {
GPUState.blend_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_SCISSOR_TEST: {
GL_CONTEXT.gen.clip_mode = GPU_USERCLIP_INSIDE;
_glApplyScissor(false);
if(GPUState.scissor_test_enabled != GL_TRUE) {
GPUState.scissor_test_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_LIGHTING: {
LIGHTING_ENABLED = GL_TRUE;
if(GPUState.lighting_enabled != GL_TRUE) {
GPUState.lighting_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_FOG:
GL_CONTEXT.gen.fog_type = GPU_FOG_TABLE;
if(GPUState.fog_enabled != GL_TRUE) {
GPUState.fog_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_COLOR_MATERIAL:
COLOR_MATERIAL_ENABLED = GL_TRUE;
if(GPUState.color_material_enabled != GL_TRUE) {
GPUState.color_material_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_SHARED_TEXTURE_PALETTE_EXT: {
SHARED_PALETTE_ENABLED = GL_TRUE;
if(GPUState.shared_palette_enabled != GL_TRUE) {
GPUState.shared_palette_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
}
break;
case GL_ALPHA_TEST: {
ALPHA_TEST_ENABLED = GL_TRUE;
_updatePVRBlend(&GL_CONTEXT);
if(GPUState.alpha_test_enabled != GL_TRUE) {
GPUState.alpha_test_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_LIGHT0:
case GL_LIGHT1:
@ -347,60 +466,106 @@ GLAPI void APIENTRY glEnable(GLenum cap) {
case GL_LIGHT4:
case GL_LIGHT5:
case GL_LIGHT6:
case GL_LIGHT7:
_glEnableLight(cap & 0xF, GL_TRUE);
case GL_LIGHT7: {
LightSource* ptr = _glLightAt(cap & 0xF);
if(ptr->isEnabled != GL_TRUE) {
ptr->isEnabled = GL_TRUE;
_glRecalcEnabledLights();
}
}
break;
case GL_NEARZ_CLIPPING_KOS:
_glEnableClipping(GL_TRUE);
if(GPUState.znear_clipping_enabled != GL_TRUE) {
GPUState.znear_clipping_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_POLYGON_OFFSET_POINT:
case GL_POLYGON_OFFSET_LINE:
case GL_POLYGON_OFFSET_FILL:
POLYGON_OFFSET_ENABLED = GL_TRUE;
if(GPUState.polygon_offset_enabled != GL_TRUE) {
GPUState.polygon_offset_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_NORMALIZE:
NORMALIZE_ENABLED = GL_TRUE;
if(GPUState.normalize_enabled != GL_TRUE) {
GPUState.normalize_enabled = GL_TRUE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_TEXTURE_TWIDDLE_KOS:
_glSetTextureTwiddle(GL_TRUE);
break;
default:
_glKosThrowError(GL_INVALID_VALUE, __func__);
break;
}
}
GLAPI void APIENTRY glDisable(GLenum cap) {
switch(cap) {
case GL_TEXTURE_2D: {
TEXTURES_ENABLED[_glGetActiveTexture()] = GL_FALSE;
} break;
case GL_TEXTURE_2D:
if(TEXTURES_ENABLED[_glGetActiveTexture()] != GL_FALSE) {
TEXTURES_ENABLED[_glGetActiveTexture()] = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_CULL_FACE: {
CULLING_ENABLED = GL_FALSE;
GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
if(GPUState.culling_enabled != GL_FALSE) {
GPUState.culling_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_DEPTH_TEST: {
DEPTH_TEST_ENABLED = GL_FALSE;
GL_CONTEXT.depth.comparison = _calc_pvr_depth_test();
if(GPUState.depth_test_enabled != GL_FALSE) {
GPUState.depth_test_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_BLEND: {
if(GPUState.blend_enabled != GL_FALSE) {
GPUState.blend_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_BLEND:
BLEND_ENABLED = GL_FALSE;
_updatePVRBlend(&GL_CONTEXT);
break;
case GL_SCISSOR_TEST: {
GL_CONTEXT.gen.clip_mode = GPU_USERCLIP_DISABLE;
if(GPUState.scissor_test_enabled != GL_FALSE) {
GPUState.scissor_test_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_LIGHTING: {
LIGHTING_ENABLED = GL_FALSE;
if(GPUState.lighting_enabled != GL_FALSE) {
GPUState.lighting_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_FOG:
GL_CONTEXT.gen.fog_type = GPU_FOG_DISABLE;
if(GPUState.fog_enabled != GL_FALSE) {
GPUState.fog_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_COLOR_MATERIAL:
COLOR_MATERIAL_ENABLED = GL_FALSE;
if(GPUState.color_material_enabled != GL_FALSE) {
GPUState.color_material_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_SHARED_TEXTURE_PALETTE_EXT: {
SHARED_PALETTE_ENABLED = GL_FALSE;
if(GPUState.shared_palette_enabled != GL_FALSE) {
GPUState.shared_palette_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
}
break;
case GL_ALPHA_TEST: {
ALPHA_TEST_ENABLED = GL_FALSE;
if(GPUState.alpha_test_enabled != GL_FALSE) {
GPUState.alpha_test_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
} break;
case GL_LIGHT0:
case GL_LIGHT1:
@ -410,20 +575,36 @@ GLAPI void APIENTRY glDisable(GLenum cap) {
case GL_LIGHT5:
case GL_LIGHT6:
case GL_LIGHT7:
_glEnableLight(cap & 0xF, GL_FALSE);
if(GPUState.lights[cap & 0xF].isEnabled) {
_glEnableLight(cap & 0xF, GL_FALSE);
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_NEARZ_CLIPPING_KOS:
_glEnableClipping(GL_FALSE);
if(GPUState.znear_clipping_enabled != GL_FALSE) {
GPUState.znear_clipping_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_POLYGON_OFFSET_POINT:
case GL_POLYGON_OFFSET_LINE:
case GL_POLYGON_OFFSET_FILL:
POLYGON_OFFSET_ENABLED = GL_FALSE;
if(GPUState.polygon_offset_enabled != GL_FALSE) {
GPUState.polygon_offset_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_NORMALIZE:
NORMALIZE_ENABLED = GL_FALSE;
if(GPUState.normalize_enabled != GL_FALSE) {
GPUState.normalize_enabled = GL_FALSE;
GPUState.is_dirty = GL_TRUE;
}
break;
case GL_TEXTURE_TWIDDLE_KOS:
_glSetTextureTwiddle(GL_FALSE);
break;
default:
_glKosThrowError(GL_INVALID_VALUE, __func__);
break;
}
}
@ -456,7 +637,7 @@ GLAPI void APIENTRY glClearDepthf(GLfloat depth) {
GLAPI void APIENTRY glClearDepth(GLfloat depth) {
/* We reverse because using invW means that farther Z == lower number */
GPUSetClearDepth(1.0f - depth);
GPUSetClearDepth(MIN(1.0f - depth, PVR_MIN_Z));
}
GLAPI void APIENTRY glDrawBuffer(GLenum mode) {
@ -470,12 +651,17 @@ GLAPI void APIENTRY glReadBuffer(GLenum mode) {
}
GLAPI void APIENTRY glDepthMask(GLboolean flag) {
GL_CONTEXT.depth.write = (flag == GL_TRUE) ? GPU_DEPTHWRITE_ENABLE : GPU_DEPTHWRITE_DISABLE;
if(GPUState.depth_mask_enabled != flag) {
GPUState.depth_mask_enabled = flag;
GPUState.is_dirty = GL_TRUE;
}
}
GLAPI void APIENTRY glDepthFunc(GLenum func) {
DEPTH_FUNC = func;
GL_CONTEXT.depth.comparison = _calc_pvr_depth_test();
if(GPUState.depth_func != func) {
GPUState.depth_func = func;
GPUState.is_dirty = GL_TRUE;
}
}
/* Hints */
@ -487,31 +673,42 @@ GLAPI void APIENTRY glHint(GLenum target, GLenum mode) {
}
}
/* Polygon Rasterization Mode */
GLAPI void APIENTRY glPolygonMode(GLenum face, GLenum mode) {
_GL_UNUSED(face);
_GL_UNUSED(mode);
}
/* Culling */
GLAPI void APIENTRY glFrontFace(GLenum mode) {
FRONT_FACE = mode;
GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
if(GPUState.front_face != mode) {
GPUState.front_face = mode;
GPUState.is_dirty = GL_TRUE;
}
}
GLAPI void APIENTRY glCullFace(GLenum mode) {
CULL_FACE = mode;
GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
}
GLenum _glGetShadeModel() {
return (GL_CONTEXT.gen.shading == GPU_SHADE_FLAT) ? GL_FLAT : GL_SMOOTH;
if(GPUState.cull_face != mode) {
GPUState.cull_face = mode;
GPUState.is_dirty = GL_TRUE;
}
}
/* Shading - Flat or Goraud */
GLAPI void APIENTRY glShadeModel(GLenum mode) {
GL_CONTEXT.gen.shading = (mode == GL_SMOOTH) ? GPU_SHADE_GOURAUD : GPU_SHADE_FLAT;
if(GPUState.shade_model != mode) {
GPUState.shade_model = mode;
GPUState.is_dirty = GL_TRUE;
}
}
/* Blending */
GLAPI void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor) {
BLEND_SFACTOR = sfactor;
BLEND_DFACTOR = dfactor;
_updatePVRBlend(&GL_CONTEXT);
if(GPUState.blend_dfactor != dfactor || GPUState.blend_sfactor != sfactor) {
GPUState.blend_sfactor = sfactor;
GPUState.blend_dfactor = dfactor;
GPUState.is_dirty = GL_TRUE;
}
}
@ -534,8 +731,15 @@ void glLineWidth(GLfloat width) {
}
void glPolygonOffset(GLfloat factor, GLfloat units) {
OFFSET_FACTOR = factor;
OFFSET_UNITS = units;
GPUState.offset_factor = factor;
GPUState.offset_units = units;
GPUState.is_dirty = GL_TRUE;
}
void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) {
_GL_UNUSED(target);
_GL_UNUSED(pname);
_GL_UNUSED(params);
}
void glGetTexParameteriv(GLenum target, GLenum pname, GLint *params) {
@ -558,18 +762,20 @@ void glPixelStorei(GLenum pname, GLint param) {
void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
if(SCISSOR_RECT.x == x &&
SCISSOR_RECT.y == y &&
SCISSOR_RECT.width == width &&
SCISSOR_RECT.height == height) {
if(GPUState.scissor_rect.x == x &&
GPUState.scissor_rect.y == y &&
GPUState.scissor_rect.width == width &&
GPUState.scissor_rect.height == height) {
return;
}
SCISSOR_RECT.x = x;
SCISSOR_RECT.y = y;
SCISSOR_RECT.width = width;
SCISSOR_RECT.height = height;
SCISSOR_RECT.applied = false;
GPUState.scissor_rect.x = x;
GPUState.scissor_rect.y = y;
GPUState.scissor_rect.width = width;
GPUState.scissor_rect.height = height;
GPUState.scissor_rect.applied = false;
GPUState.is_dirty = GL_TRUE; // FIXME: do we need this?
_glApplyScissor(false);
}
@ -599,12 +805,12 @@ void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
*/
void _glApplyScissor(bool force) {
/* Don't do anyting if clipping is disabled */
if(GL_CONTEXT.gen.clip_mode == GPU_USERCLIP_DISABLE) {
if(!GPUState.scissor_test_enabled) {
return;
}
/* Don't apply if we already applied - nothing changed */
if(SCISSOR_RECT.applied && !force) {
if(GPUState.scissor_rect.applied && !force) {
return;
}
@ -614,45 +820,61 @@ void _glApplyScissor(bool force) {
const VideoMode* vid_mode = GetVideoMode();
GLsizei scissor_width = MAX(MIN(SCISSOR_RECT.width, vid_mode->width), 0);
GLsizei scissor_height = MAX(MIN(SCISSOR_RECT.height, vid_mode->height), 0);
GLsizei scissor_width = MAX(MIN(GPUState.scissor_rect.width, vid_mode->width), 0);
GLsizei scissor_height = MAX(MIN(GPUState.scissor_rect.height, vid_mode->height), 0);
/* force the origin to the lower left-hand corner of the screen */
miny = (vid_mode->height - scissor_height) - SCISSOR_RECT.y;
maxx = (scissor_width + SCISSOR_RECT.x);
miny = (vid_mode->height - scissor_height) - GPUState.scissor_rect.y;
maxx = (scissor_width + GPUState.scissor_rect.x);
maxy = (scissor_height + miny);
/* load command structure while mapping screen coords to TA tiles */
c.flags = GPU_CMD_USERCLIP;
c.d1 = c.d2 = c.d3 = 0;
c.sx = CLAMP(SCISSOR_RECT.x / 32, 0, vid_mode->width / 32);
c.sy = CLAMP(miny / 32, 0, vid_mode->height / 32);
c.ex = CLAMP((maxx / 32) - 1, 0, vid_mode->width / 32);
c.ey = CLAMP((maxy / 32) - 1, 0, vid_mode->height / 32);
uint16_t vw = vid_mode->width >> 5;
uint16_t vh = vid_mode->height >> 5;
c.sx = CLAMP(GPUState.scissor_rect.x >> 5, 0, vw);
c.sy = CLAMP(miny >> 5, 0, vh);
c.ex = CLAMP((maxx >> 5) - 1, 0, vw);
c.ey = CLAMP((maxy >> 5) - 1, 0, vh);
aligned_vector_push_back(&_glOpaquePolyList()->vector, &c, 1);
aligned_vector_push_back(&_glPunchThruPolyList()->vector, &c, 1);
aligned_vector_push_back(&_glTransparentPolyList()->vector, &c, 1);
SCISSOR_RECT.applied = true;
GPUState.scissor_rect.applied = true;
}
void glStencilFunc(GLenum func, GLint ref, GLuint mask) {
_GL_UNUSED(func);
_GL_UNUSED(ref);
_GL_UNUSED(mask);
}
void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) {
_GL_UNUSED(sfail);
_GL_UNUSED(dpfail);
_GL_UNUSED(dppass);
}
GLboolean APIENTRY glIsEnabled(GLenum cap) {
switch(cap) {
case GL_DEPTH_TEST:
return DEPTH_TEST_ENABLED;
return GPUState.depth_test_enabled;
case GL_SCISSOR_TEST:
return GL_CONTEXT.gen.clip_mode == GPU_USERCLIP_INSIDE;
return GPUState.scissor_test_enabled;
case GL_CULL_FACE:
return CULLING_ENABLED;
return GPUState.culling_enabled;
case GL_LIGHTING:
return LIGHTING_ENABLED;
return GPUState.lighting_enabled;
case GL_BLEND:
return BLEND_ENABLED;
return GPUState.blend_enabled;
case GL_POLYGON_OFFSET_POINT:
case GL_POLYGON_OFFSET_LINE:
case GL_POLYGON_OFFSET_FILL:
return POLYGON_OFFSET_ENABLED;
return GPUState.polygon_offset_enabled;
}
return GL_FALSE;
@ -695,27 +917,25 @@ void APIENTRY glGetBooleanv(GLenum pname, GLboolean* params) {
} break;
default:
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
}
}
void APIENTRY glGetFloatv(GLenum pname, GLfloat* params) {
switch(pname) {
case GL_PROJECTION_MATRIX:
FASTCPY4(params, _glGetProjectionMatrix(), sizeof(float) * 16);
MEMCPY4(params, _glGetProjectionMatrix(), sizeof(float) * 16);
break;
case GL_MODELVIEW_MATRIX:
FASTCPY4(params, _glGetModelViewMatrix(), sizeof(float) * 16);
MEMCPY4(params, _glGetModelViewMatrix(), sizeof(float) * 16);
break;
case GL_POLYGON_OFFSET_FACTOR:
*params = OFFSET_FACTOR;
*params = GPUState.offset_factor;
break;
case GL_POLYGON_OFFSET_UNITS:
*params = OFFSET_UNITS;
*params = GPUState.offset_units;
break;
default:
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
break;
}
}
@ -723,19 +943,19 @@ void APIENTRY glGetFloatv(GLenum pname, GLfloat* params) {
void APIENTRY glGetIntegerv(GLenum pname, GLint *params) {
switch(pname) {
case GL_MAX_LIGHTS:
*params = MAX_LIGHTS;
*params = MAX_GLDC_LIGHTS;
break;
case GL_TEXTURE_BINDING_2D:
*params = (_glGetBoundTexture()) ? _glGetBoundTexture()->index : 0;
break;
case GL_DEPTH_FUNC:
*params = DEPTH_FUNC;
*params = GPUState.depth_func;
break;
case GL_BLEND_SRC:
*params = BLEND_SFACTOR;
*params = GPUState.blend_sfactor;
break;
case GL_BLEND_DST:
*params = BLEND_DFACTOR;
*params = GPUState.blend_dfactor;
break;
case GL_MAX_TEXTURE_SIZE:
*params = MAX_TEXTURE_SIZE;
@ -765,9 +985,12 @@ void APIENTRY glGetIntegerv(GLenum pname, GLint *params) {
case GL_FREE_CONTIGUOUS_TEXTURE_MEMORY_KOS:
*params = _glFreeContiguousTextureMemory();
break;
case GL_TEXTURE_INTERNAL_FORMAT_KOS:
*params = _glGetTextureInternalFormat();
break;
default:
_glKosThrowError(GL_INVALID_ENUM, __func__);
_glKosPrintError();
break;
}
}
@ -784,7 +1007,7 @@ const GLubyte *glGetString(GLenum name) {
return (const GLubyte*) "1.2 (partial) - GLdc 1.1";
case GL_EXTENSIONS:
return (const GLubyte*) "GL_ARB_framebuffer_object, GL_ARB_multitexture, GL_ARB_texture_rg, GL_EXT_paletted_texture, GL_EXT_shared_texture_palette, GL_KOS_multiple_shared_palette, GL_ARB_vertex_array_bgra, GL_ARB_vertex_type_2_10_10_10_rev, GL_KOS_texture_memory_management, GL_ATI_meminfo";
return (const GLubyte*)"GL_ARB_framebuffer_object, GL_ARB_multitexture, GL_ARB_texture_rg, GL_OES_compressed_paletted_texture, GL_EXT_paletted_texture, GL_EXT_shared_texture_palette, GL_KOS_multiple_shared_palette, GL_ARB_vertex_array_bgra, GL_ARB_vertex_type_2_10_10_10_rev, GL_KOS_texture_memory_management, GL_ATI_meminfo";
}
return (const GLubyte*) "GL_KOS_ERROR: ENUM Unsupported\n";

File diff suppressed because it is too large Load Diff

View File

@ -13,4 +13,4 @@ typedef struct {
* but we're not using that for now, so having W here makes the code
* simpler */
float w;
} Vertex;
} __attribute__ ((aligned (32))) Vertex;

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,158 +0,0 @@
# Summary
yalloc is a memory efficient allocator which is intended for embedded
applications that only have a low amount of RAM and want to maximize its
utilization. Properties of the allocator:
- pools can be up to 128k
- user data is 32bit aligned
- 4 bytes overhead per allocation
- supports defragmentation
- uses a free list for first fit allocation strategy (most recently freed
blocks are used first)
- extensively tested (see section below)
- MIT license
# Defragmentation
This feature was the initial motivation for this implementation. Especially
when dealing with highly memory constrained environments fragmenting memory
pools can be annoying. For this reason this implementation supports
defragmentation which moves all allocated blocks into a contiguous range at the
beginning of the pool, leaving a maximized free range at the end.
As there is no garbage collector or other runtime system involved that updates
the references, the application must do so. This is done in three steps:
1. yalloc_defrag_start() is called. This calculates the new
post-defragmentation-addresses for all allocations, but otherwise leaves
the allocations untouched.
2. yalloc_defrag_address() is called by the application for every pointer that
points to an allocation. It returns the post-defragmentation-address for
the allocation. The application must update all its relevant pointers this
way. Care must be taken not not yet dereference that moved pointers. If the
application works with hierarchical data then this can easily be done by
updating the pointers button up (first the leafs then their parents).
3. yalloc_defrag_commit() is called to finally perform the defragmentation.
All allocated blocks are moved to their post-defragmentation-address and
the application can continue using the pool the normal way.
It is up to the application when (and if) it performs defragmentation. One
strategy would be to delay it until an allocation failure. Another approach
would be to perform the defragmentation regularly when there is nothing else to
do.
# Configurable Defines
INTERNAL_VALIDATE
If this is not defined on the compiler commandline it will be defined as 0 if
NDEBUG is defined and otherwise as 1. If you want to disable internal
validation when NDEBUG is not defined then define INERNAL_VALIDATE as 0 on the
compiler commandline.
If it is nonzero the heap will be validated via a bunch of assert() calls at
the end of every function that modifies the heap. This has roughly O(N*M)
overhead where N is the number of allocated blocks and M the number of free
blocks in a heap. For applications with enough live allocations this will get
significant.
YALLOC_VALGRIND
If this is defined in yalloc.c and NVALGRIND is not defined then
valgrind/memcheck.h is included and the the allocator functions tell valgrind
about the pool, the allocations and makes the block headers inaccessible outside
of yalloc-functions. This allows valgrind to detect a lot of the accidents that
can happen when dealing dynamic memory. This also adds some overhead for every
yalloc-call because most of them will "unprotect" the internal structure on
entry and "protect" it again (marking it as inaccessible for valgrind) before
returning.
# Tests
The tests rely on internal validation of the pool (see INTERNAL_VALIDATE) to
check that no assumptions about the internal structure of the pool are
violated. They additionally check for correctness of observations that can be
made by using the public functions of the allocator (like checking if user data
stays unmodified). There are a few different scripts that run tests:
- run_coverage.sh runs a bunch of testfunctions that are carefully crafted to
cover all code paths. Coverage data is generated by clang and a summary is
shown at the end of the test.
- run_valgrind.sh tests if the valgrind integration is working as expected,
runs the functions from the coverage test and some randomly generated
testcases under valgrind.
- run_libfuzzer.sh uses libfuzzer from clang to generate interesting testcases
and runs them in multiple jobs in parallel for 10 seconds. It also generates
coverage data at the end (it always got 100% coverage in my testruns).
All tests exit with 0 and print "All fine!" at the end if there where no
errors. Coverage deficits are not counted as error, so you have to look at the
summary (they should show 100% coverage!).
# Implementation Details
The Headers and the user data are 32bit aligned. Headers have two 16bit fields
where the high 15 bits represent offsets (relative to the pools address) to the
previous/next block. The macros HDR_PTR() and HDR_OFFSET() are used to
translate an offset to an address and back. The 32bit alignment is exploited to
allow pools of up to 128k with that 15 significant bits.
A pool is always occupied by non-overlapping blocks that link to their
previous/next block in address order via the prev/next field of Header.
Free blocks are always joined: No two free blocks will ever be neighbors.
Free blocks have an additional header of the same structure. This additional
header is used to build a list of free blocks (independent of their address
order).
yalloc_free() will insert the freed block to the front of the free list.
yalloc_alloc() searches that list front to back and takes the first block that
is big enough to satisfy the allocation.
There is always a Header at the front and at the end of the pool. The Header at
the end is degenerate: It is marked as "used" but has no next block (which is
usually used to determine the size of a block).
The prev-field of the very first block in the pool has special meaning: It
points to the first free block in the pool. Or, if the pool is currently
defragmenting (after yalloc_defrag_start() and before yalloc_defrag_commit()),
points to the last header of the pool. This state can be recognized by checking
if it points to an empty block (normal pool state) or a used block
(defragmentation in progress). This logic can be seen in
yalloc_defrag_in_progress().
The lowest bit of next/prev have special meaning:
- low bit of prev is set for free blocks
- low bit of next is set for blocks with 32bit padding after the user data.
This is needed when a block is allocated from a free block that leaves only
4 free bytes after the user data... which is not enough to insert a
free-header (which is needs 8 bytes). The padding will be reclaimed when
that block is freed or when the pool is defragmented. The predicate
isPadded() can be used to test if a block is padded. Free blocks are never
padded.
The predicate isNil() can be used to test if an offset points nowhere (it tests
if all 15 high bits of an offset are 1). The constant NIL has all but the
lowest bit set. It is used to set offsets to point to nowhere, and in some
places it is used to mask out the actual address bits of an offset. This should
be kept in mind when modifying the code and updating prev/next: Think carefully
if you have to preserve the low bit when updating an offset!
Defragmentation is done in two phases: First the user calls
yalloc_defrag_start(). This will put the pool in a special state where no
alloc/free-calls are allowed. In this state the prev-fields of the used blocks
have a special meaning: They store the offset that the block will have after
defragmentation finished. This information is used by yalloc_defrag_address()
which can be called by the application to query the new addresses for its
allocations. After the application has updated all its pointers it must call
yalloc_defrag_commit() which moves all used blocks in contiguous space at the
beginning of the pool, leaving one maximized free block at the end.

View File

@ -1,802 +0,0 @@
#include "yalloc.h"
#include "yalloc_internals.h"
#include <assert.h>
#include <string.h>
#define ALIGN(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#if defined(YALLOC_VALGRIND) && !defined(NVALGRIND)
# define USE_VALGRIND 1
#else
# define USE_VALGRIND 0
#endif
#if USE_VALGRIND
# include <valgrind/memcheck.h>
#else
# define VALGRIND_MAKE_MEM_UNDEFINED(p, s) ((void)0)
# define VALGRIND_MAKE_MEM_DEFINED(p, s) ((void)0)
# define VALGRIND_MAKE_MEM_NOACCESS(p, s) ((void)0)
# define VALGRIND_CREATE_MEMPOOL(pool, rz, z) ((void)0)
# define VALGRIND_MEMPOOL_ALLOC(pool, p, s) ((void)0)
# define VALGRIND_MEMPOOL_FREE(pool, p) ((void)0)
# define VALGRIND_MEMPOOL_CHANGE(pool, a, b, s) ((void)0)
#endif
#define MARK_NEW_FREE_HDR(p) VALGRIND_MAKE_MEM_UNDEFINED(p, sizeof(Header) * 2)
#define MARK_NEW_HDR(p) VALGRIND_MAKE_MEM_UNDEFINED(p, sizeof(Header))
#define PROTECT_HDR(p) VALGRIND_MAKE_MEM_NOACCESS(p, sizeof(Header))
#define PROTECT_FREE_HDR(p) VALGRIND_MAKE_MEM_NOACCESS(p, sizeof(Header) * 2)
#define UNPROTECT_HDR(p) VALGRIND_MAKE_MEM_DEFINED(p, sizeof(Header))
#define UNPROTECT_FREE_HDR(p) VALGRIND_MAKE_MEM_DEFINED(p, sizeof(Header) * 2)
#if USE_VALGRIND
static void _unprotect_pool(void * pool)
{
Header * cur = (Header*)pool;
for (;;)
{
UNPROTECT_HDR(cur);
if (isFree(cur))
UNPROTECT_HDR(cur + 1);
if (isNil(cur->next))
break;
cur = HDR_PTR(cur->next);
}
}
static void _protect_pool(void * pool)
{
Header * cur = (Header*)pool;
while (cur)
{
Header * next = isNil(cur->next) ? NULL : HDR_PTR(cur->next);
if (isFree(cur))
VALGRIND_MAKE_MEM_NOACCESS(cur, (char*)next - (char*)cur);
else
PROTECT_HDR(cur);
cur = next;
}
}
#define assert_is_pool(pool) assert(VALGRIND_MEMPOOL_EXISTS(pool));
#else
static void _unprotect_pool(void * pool){(void)pool;}
static void _protect_pool(void * pool){(void)pool;}
#define assert_is_pool(pool) ((void)0)
#endif
// internal version that does not unprotect/protect the pool
static int _yalloc_defrag_in_progress(void * pool)
{
// fragmentation is indicated by a free list with one entry: the last block of the pool, which has its "free"-bit cleared.
Header * p = (Header*)pool;
if (isNil(p->prev))
return 0;
return !(HDR_PTR(p->prev)->prev & 1);
}
int yalloc_defrag_in_progress(void * pool)
{
_unprotect_pool(pool);
int ret = _yalloc_defrag_in_progress(pool);
_protect_pool(pool);
return ret;
}
#if YALLOC_INTERNAL_VALIDATE
static size_t _count_free_list_occurences(Header * pool, Header * blk)
{
int n = 0;
if (!isNil(pool->prev))
{
Header * cur = HDR_PTR(pool->prev);
for (;;)
{
if (cur == blk)
++n;
if (isNil(cur[1].next))
break;
cur = HDR_PTR(cur[1].next);
}
}
return n;
}
static size_t _count_addr_list_occurences(Header * pool, Header * blk)
{
size_t n = 0;
Header * cur = pool;
for (;;)
{
if (cur == blk)
++n;
if (isNil(cur->next))
break;
cur = HDR_PTR(cur->next);
}
return n;
}
static void _validate_user_ptr(void * pool, void * p)
{
Header * hdr = (Header*)p - 1;
size_t n = _count_addr_list_occurences((Header*)pool, hdr);
assert(n == 1 && !isFree(hdr));
}
/**
Validates if all the invariants of a pool are intact.
This is very expensive when there are enough blocks in the heap (quadratic complexity!).
*/
static void _yalloc_validate(void * pool_)
{
Header * pool = (Header*)pool_;
Header * cur = pool;
assert(!isNil(pool->next)); // there must always be at least two blocks: a free/used one and the final block at the end
if (_yalloc_defrag_in_progress(pool))
{
Header * prevUsed = NULL;
while (!isNil(cur->next))
{
if (!isFree(cur))
{ // it is a used block
Header * newAddr = cur == pool ? pool : HDR_PTR(cur->prev);
assert(newAddr <= cur);
assert(newAddr >= pool);
if (prevUsed)
{
Header * prevNewAddr = prevUsed == pool ? pool : HDR_PTR(prevUsed->prev);
size_t prevBruttoSize = (char*)HDR_PTR(prevUsed->next) - (char*)prevUsed;
if (isPadded(prevUsed))
prevBruttoSize -= 4; // remove padding
assert((char*)newAddr == (char*)prevNewAddr + prevBruttoSize);
}
else
{
assert(newAddr == pool);
}
prevUsed = cur;
}
cur = HDR_PTR(cur->next);
}
assert(cur == HDR_PTR(pool->prev)); // the free-list should point to the last block
assert(!isFree(cur)); // the last block must not be free
}
else
{
Header * prev = NULL;
// iterate blocks in address order
for (;;)
{
if (prev)
{
Header * x = HDR_PTR(cur->prev);
assert(x == prev);
}
int n = _count_free_list_occurences(pool, cur);
if (isFree(cur))
{ // it is a free block
assert(n == 1);
assert(!isPadded(cur)); // free blocks must have a zero padding-bit
if (prev)
{
assert(!isFree(prev)); // free blocks must not be direct neighbours
}
}
else
{
assert(n == 0);
}
if (isNil(cur->next))
break;
Header * next = HDR_PTR(cur->next);
assert((char*)next >= (char*)cur + sizeof(Header) * 2);
prev = cur;
cur = next;
}
assert(isNil(cur->next));
if (!isNil(pool->prev))
{
// iterate free-list
Header * f = HDR_PTR(pool->prev);
assert(isNil(f[1].prev));
for (;;)
{
assert(isFree(f)); // must be free
int n = _count_addr_list_occurences(pool, f);
assert(n == 1);
if (isNil(f[1].next))
break;
f = HDR_PTR(f[1].next);
}
}
}
}
#else
static void _yalloc_validate(void * pool){(void)pool;}
static void _validate_user_ptr(void * pool, void * p){(void)pool; (void)p;}
#endif
int yalloc_init(void * pool, size_t size)
{
if (size > MAX_POOL_SIZE)
return -1;
// TODO: Error when pool is not properly aligned
// TODO: Error when size is not a multiple of the alignment?
while (size % sizeof(Header))
--size;
if(size < sizeof(Header) * 3)
return -1;
VALGRIND_CREATE_MEMPOOL(pool, 0, 0);
Header * first = (Header*)pool;
Header * last = (Header*)((char*)pool + size) - 1;
MARK_NEW_FREE_HDR(first);
MARK_NEW_HDR(first);
first->prev = HDR_OFFSET(first) | 1;
first->next = HDR_OFFSET(last);
first[1].prev = NIL;
first[1].next = NIL;
last->prev = HDR_OFFSET(first);
last->next = NIL;
_unprotect_pool(pool);
_yalloc_validate(pool);
_protect_pool(pool);
return 0;
}
void yalloc_deinit(void * pool)
{
#if USE_VALGRIND
VALGRIND_DESTROY_MEMPOOL(pool);
Header * last = (Header*)pool;
UNPROTECT_HDR(last);
while (!isNil(last->next))
{
Header * next = HDR_PTR(last->next);
UNPROTECT_HDR(next);
last = next;
}
VALGRIND_MAKE_MEM_UNDEFINED(pool, (char*)(last + 1) - (char*)pool);
#else
(void)pool;
#endif
}
void * yalloc_alloc(void * pool, size_t size)
{
assert_is_pool(pool);
_unprotect_pool(pool);
assert(!_yalloc_defrag_in_progress(pool));
_yalloc_validate(pool);
if (!size)
{
_protect_pool(pool);
return NULL;
}
Header * root = (Header*)pool;
if (isNil(root->prev))
{
_protect_pool(pool);
return NULL; /* no free block, no chance to allocate anything */ // TODO: Just read up which C standard supports single line comments and then fucking use them!
}
/* round up to alignment */
size = ALIGN(size, 64);
size_t bruttoSize = size + sizeof(Header);
Header * prev = NULL;
Header * cur = HDR_PTR(root->prev);
for (;;)
{
size_t curSize = (char*)HDR_PTR(cur->next) - (char*)cur; /* size of the block, including its header */
if (curSize >= bruttoSize) // it is big enough
{
// take action for unused space in the free block
if (curSize >= bruttoSize + sizeof(Header) * 2)
{ // the leftover space is big enough to make it a free block
// Build a free block from the unused space and insert it into the list of free blocks after the current free block
Header * tail = (Header*)((char*)cur + bruttoSize);
MARK_NEW_FREE_HDR(tail);
// update address-order-list
tail->next = cur->next;
tail->prev = HDR_OFFSET(cur) | 1;
HDR_PTR(cur->next)->prev = HDR_OFFSET(tail); // NOTE: We know the next block is used because free blocks are never neighbours. So we don't have to care about the lower bit which would be set for the prev of a free block.
cur->next = HDR_OFFSET(tail);
// update list of free blocks
tail[1].next = cur[1].next;
// NOTE: tail[1].prev is updated in the common path below (assignment to "HDR_PTR(cur[1].next)[1].prev")
if (!isNil(cur[1].next))
HDR_PTR(cur[1].next)[1].prev = HDR_OFFSET(tail);
cur[1].next = HDR_OFFSET(tail);
}
else if (curSize > bruttoSize)
{ // there will be unused space, but not enough to insert a free header
internal_assert(curSize - bruttoSize == sizeof(Header)); // unused space must be enough to build a free-block or it should be exactly the size of a Header
cur->next |= 1; // set marker for "has unused trailing space"
}
else
{
internal_assert(curSize == bruttoSize);
}
cur->prev &= NIL; // clear marker for "is a free block"
// remove from linked list of free blocks
if (prev)
prev[1].next = cur[1].next;
else
{
uint32_t freeBit = isFree(root);
root->prev = (cur[1].next & NIL) | freeBit;
}
if (!isNil(cur[1].next))
HDR_PTR(cur[1].next)[1].prev = prev ? HDR_OFFSET(prev) : NIL;
_yalloc_validate(pool);
VALGRIND_MEMPOOL_ALLOC(pool, cur + 1, size);
_protect_pool(pool);
return cur + 1; // return address after the header
}
if (isNil(cur[1].next))
break;
prev = cur;
cur = HDR_PTR(cur[1].next);
}
_yalloc_validate(pool);
_protect_pool(pool);
return NULL;
}
// Removes a block from the free-list and moves the pools first-free-bock pointer to its successor if it pointed to that block.
static void unlink_from_free_list(Header * pool, Header * blk)
{
// update the pools pointer to the first block in the free list if necessary
if (isNil(blk[1].prev))
{ // the block is the first in the free-list
// make the pools first-free-pointer point to the next in the free list
uint32_t freeBit = isFree(pool);
pool->prev = (blk[1].next & NIL) | freeBit;
}
else
HDR_PTR(blk[1].prev)[1].next = blk[1].next;
if (!isNil(blk[1].next))
HDR_PTR(blk[1].next)[1].prev = blk[1].prev;
}
size_t yalloc_block_size(void * pool, void * p)
{
Header * a = (Header*)p - 1;
UNPROTECT_HDR(a);
Header * b = HDR_PTR(a->next);
size_t payloadSize = (char*)b - (char*)p;
if (isPadded(a))
payloadSize -= sizeof(Header);
PROTECT_HDR(a);
return payloadSize;
}
void yalloc_free(void * pool_, void * p)
{
assert_is_pool(pool_);
assert(!yalloc_defrag_in_progress(pool_));
if (!p)
return;
_unprotect_pool(pool_);
Header * pool = (Header*)pool_;
Header * cur = (Header*)p - 1;
// get pointers to previous/next block in address order
Header * prev = cur == pool || isNil(cur->prev) ? NULL : HDR_PTR(cur->prev);
Header * next = isNil(cur->next) ? NULL : HDR_PTR(cur->next);
int prevFree = prev && isFree(prev);
int nextFree = next && isFree(next);
#if USE_VALGRIND
{
unsigned errs = VALGRIND_COUNT_ERRORS;
VALGRIND_MEMPOOL_FREE(pool, p);
if (VALGRIND_COUNT_ERRORS > errs)
{ // early exit if the free was invalid (so we get a valgrind error and don't mess up the pool, which is helpful for testing if invalid frees are detected by valgrind)
_protect_pool(pool_);
return;
}
}
#endif
_validate_user_ptr(pool_, p);
if (prevFree && nextFree)
{ // the freed block has two free neighbors
unlink_from_free_list(pool, prev);
unlink_from_free_list(pool, next);
// join prev, cur and next
prev->next = next->next;
HDR_PTR(next->next)->prev = cur->prev;
// prev is now the block we want to push onto the free-list
cur = prev;
}
else if (prevFree)
{
unlink_from_free_list(pool, prev);
// join prev and cur
prev->next = cur->next;
HDR_PTR(cur->next)->prev = cur->prev;
// prev is now the block we want to push onto the free-list
cur = prev;
}
else if (nextFree)
{
unlink_from_free_list(pool, next);
// join cur and next
cur->next = next->next;
HDR_PTR(next->next)->prev = next->prev & NIL;
}
// if there is a previous block and that block has padding then we want to grow the new free block into that padding
if (cur != pool && !isNil(cur->prev))
{ // there is a previous block
Header * left = HDR_PTR(cur->prev);
if (isPadded(left))
{ // the previous block has padding, so extend the current block to consume move the padding to the current free block
Header * grown = cur - 1;
MARK_NEW_HDR(grown);
grown->next = cur->next;
grown->prev = cur->prev;
left->next = HDR_OFFSET(grown);
if (!isNil(cur->next))
HDR_PTR(cur->next)->prev = HDR_OFFSET(grown);
cur = grown;
}
}
cur->prev |= 1; // it becomes a free block
cur->next &= NIL; // reset padding-bit
UNPROTECT_HDR(cur + 1);
cur[1].prev = NIL; // it will be the first free block in the free list, so it has no prevFree
if (!isNil(pool->prev))
{ // the free-list was already non-empty
HDR_PTR(pool->prev)[1].prev = HDR_OFFSET(cur); // make the first entry in the free list point back to the new free block (it will become the first one)
cur[1].next = pool->prev; // the next free block is the first of the old free-list
}
else
cur[1].next = NIL; // free-list was empty, so there is no successor
VALGRIND_MAKE_MEM_NOACCESS(cur + 2, (char*)HDR_PTR(cur->next) - (char*)(cur + 2));
// now the freed block is the first in the free-list
// update the offset to the first element of the free list
uint32_t freeBit = isFree(pool); // remember the free-bit of the offset
pool->prev = HDR_OFFSET(cur) | freeBit; // update the offset and restore the free-bit
_yalloc_validate(pool);
_protect_pool(pool);
}
size_t yalloc_count_free(void * pool_)
{
assert_is_pool(pool_);
_unprotect_pool(pool_);
assert(!_yalloc_defrag_in_progress(pool_));
Header * pool = (Header*)pool_;
size_t bruttoFree = 0;
Header * cur = pool;
_yalloc_validate(pool);
for (;;)
{
if (isFree(cur))
{ // it is a free block
bruttoFree += (char*)HDR_PTR(cur->next) - (char*)cur;
}
else
{ // it is a used block
if (isPadded(cur))
{ // the used block is padded
bruttoFree += sizeof(Header);
}
}
if (isNil(cur->next))
break;
cur = HDR_PTR(cur->next);
}
_protect_pool(pool);
if (bruttoFree < sizeof(Header))
{
internal_assert(!bruttoFree); // free space should always be a multiple of sizeof(Header)
return 0;
}
return bruttoFree - sizeof(Header);
}
size_t yalloc_count_continuous(void * pool_)
{
assert_is_pool(pool_);
_unprotect_pool(pool_);
assert(!_yalloc_defrag_in_progress(pool_));
Header * pool = (Header*)pool_;
size_t largestFree = 0;
Header * cur = pool;
_yalloc_validate(pool);
for (;;)
{
if (isFree(cur))
{ // it is a free block
size_t temp = (uintptr_t)HDR_PTR(cur->next) - (uintptr_t)cur;
if(temp > largestFree)
largestFree = temp;
}
if (isNil(cur->next))
break;
cur = HDR_PTR(cur->next);
}
_protect_pool(pool);
if (largestFree < sizeof(Header))
{
internal_assert(!largestFree); // free space should always be a multiple of sizeof(Header)
return 0;
}
return largestFree - sizeof(Header);
}
void * yalloc_first_used(void * pool)
{
assert_is_pool(pool);
_unprotect_pool(pool);
Header * blk = (Header*)pool;
while (!isNil(blk->next))
{
if (!isFree(blk))
{
_protect_pool(pool);
return blk + 1;
}
blk = HDR_PTR(blk->next);
}
_protect_pool(pool);
return NULL;
}
void * yalloc_next_used(void * pool, void * p)
{
assert_is_pool(pool);
_unprotect_pool(pool);
_validate_user_ptr(pool, p);
Header * prev = (Header*)p - 1;
assert(!isNil(prev->next)); // the last block should never end up as input to this function (because it is not user-visible)
Header * blk = HDR_PTR(prev->next);
while (!isNil(blk->next))
{
if (!isFree(blk))
{
_protect_pool(pool);
return blk + 1;
}
blk = HDR_PTR(blk->next);
}
_protect_pool(pool);
return NULL;
}
void yalloc_defrag_start(void * pool_)
{
assert_is_pool(pool_);
_unprotect_pool(pool_);
assert(!_yalloc_defrag_in_progress(pool_));
Header * pool = (Header*)pool_;
// iterate over all blocks in address order and store the post-defragment address of used blocks in their "prev" field
size_t end = 0; // offset for the next used block
Header * blk = (Header*)pool;
for (; !isNil(blk->next); blk = HDR_PTR(blk->next))
{
if (!isFree(blk))
{ // it is a used block
blk->prev = end >> 1;
internal_assert((char*)HDR_PTR(blk->prev) == (char*)pool + end);
size_t bruttoSize = (char*)HDR_PTR(blk->next) - (char*)blk;
if (isPadded(blk))
{ // the block is padded
bruttoSize -= sizeof(Header);
}
end += bruttoSize;
internal_assert(end % sizeof(Header) == 0);
}
}
// blk is now the last block (the dummy "used" block at the end of the pool)
internal_assert(isNil(blk->next));
internal_assert(!isFree(blk));
// mark the pool as "defragementation in progress"
uint32_t freeBit = isFree(pool);
pool->prev = (HDR_OFFSET(blk) & NIL) | freeBit;
_yalloc_validate(pool);
internal_assert(yalloc_defrag_in_progress(pool));
_protect_pool(pool);
}
void * yalloc_defrag_address(void * pool_, void * p)
{
assert_is_pool(pool_);
assert(yalloc_defrag_in_progress(pool_));
if (!p)
return NULL;
Header * pool = (Header*)pool_;
_unprotect_pool(pool);
_validate_user_ptr(pool_, p);
if (pool + 1 == p)
return pool + 1; // "prev" of the first block points to the last used block to mark the pool as "defragmentation in progress"
Header * blk = (Header*)p - 1;
void * defragP = HDR_PTR(blk->prev) + 1;
_protect_pool(pool);
return defragP;
}
void yalloc_defrag_commit(void * pool_)
{
assert_is_pool(pool_);
_unprotect_pool(pool_);
assert(_yalloc_defrag_in_progress(pool_));
Header * pool = (Header*)pool_;
// iterate over all blocks in address order and move them
size_t end = 0; // offset for the next used block
Header * blk = pool;
Header * lastUsed = NULL;
while (!isNil(blk->next))
{
if (!isFree(blk))
{ // it is a used block
size_t bruttoSize = (char*)HDR_PTR(blk->next) - (char*)blk;
if (isPadded(blk))
{ // the block is padded
bruttoSize -= sizeof(Header);
}
Header * next = HDR_PTR(blk->next);
blk->prev = lastUsed ? HDR_OFFSET(lastUsed) : NIL;
blk->next = (end + bruttoSize) >> 1;
lastUsed = (Header*)((char*)pool + end);
VALGRIND_MAKE_MEM_UNDEFINED(lastUsed, (char*)blk - (char*)lastUsed);
memmove(lastUsed, blk, bruttoSize);
VALGRIND_MEMPOOL_CHANGE(pool, blk + 1, lastUsed + 1, bruttoSize - sizeof(Header));
end += bruttoSize;
blk = next;
}
else
blk = HDR_PTR(blk->next);
}
// blk is now the last block (the dummy "used" block at the end of the pool)
internal_assert(isNil(blk->next));
internal_assert(!isFree(blk));
if (lastUsed)
{
Header * gap = HDR_PTR(lastUsed->next);
if (gap == blk)
{ // there is no gap
pool->prev = NIL; // the free list is empty
blk->prev = HDR_OFFSET(lastUsed);
}
else if (blk - gap > 1)
{ // the gap is big enouogh for a free Header
// set a free list that contains the gap as only element
gap->prev = HDR_OFFSET(lastUsed) | 1;
gap->next = HDR_OFFSET(blk);
gap[1].prev = NIL;
gap[1].next = NIL;
pool->prev = blk->prev = HDR_OFFSET(gap);
}
else
{ // there is a gap, but it is too small to be used as free-list-node, so just make it padding of the last used block
lastUsed->next = HDR_OFFSET(blk) | 1;
pool->prev = NIL;
blk->prev = HDR_OFFSET(lastUsed);
}
}
else
{ // the pool is empty
pool->prev = 1;
}
internal_assert(!_yalloc_defrag_in_progress(pool));
_yalloc_validate(pool);
_protect_pool(pool);
}

View File

@ -1,176 +0,0 @@
/**
@file
API of the yalloc allocator.
*/
#ifndef YALLOC_H
#define YALLOC_H
#include <stddef.h>
/**
Maximum supported pool size. yalloc_init() will fail for larger pools.
*/
#define MAX_POOL_SIZE ((2 << 24) - 4)
/**
Creates a pool inside a given buffer.
Pools must be deinitialized with yalloc_deinit() when they are no longer needed.
@param pool The starting address of the pool. It must have at least 16bit
alignment (internal structure uses 16bit integers). Allocations are placed at
32bit boundaries starting from this address, so if the user data should be
32bit aligned then this address has to be 32bit aligned. Typically an address
of static memory, or an array on the stack is used if the pool is only used
temporarily.
@param size Size of the pool.
@return 0 on success, nonzero if the size is not supported.
*/
int yalloc_init(void * pool, size_t size);
/**
Deinitializes the buffer that is used by the pool and makes it available for other use.
The content of the buffer is undefined after this.
@param pool The starting address of an initialized pool.
*/
void yalloc_deinit(void * pool);
/**
Allocates a block of memory from a pool.
This function mimics malloc().
The pool must not be in the "defragmenting" state when this function is called.
@param pool The starting address of an initialized pool.
@param size Number of bytes to allocate.
@return Allocated buffer or \c NULL if there was no free range that could serve
the allocation. See @ref yalloc_defrag_start() for a way to remove
fragmentation which may cause allocations to fail even when there is enough
space in total.
*/
void * yalloc_alloc(void * pool, size_t size);
/**
Returns an allocation to a pool.
This function mimics free().
The pool must not be in the "defragmenting" state when this function is called.
@param pool The starting address of the initialized pool the allocation comes from.
@param p An address that was returned from yalloc_alloc() of the same pool.
*/
void yalloc_free(void * pool, void * p);
/**
Returns the maximum size of a successful allocation (assuming a completely unfragmented heap).
After defragmentation the first allocation with the returned size is guaranteed to succeed.
@param pool The starting address of an initialized pool.
@return Number of bytes that can be allocated (assuming the pool is defragmented).
*/
size_t yalloc_count_free(void * pool);
/**
Returns the maximum continuous free area.
@param pool The starting address of an initialized pool.
@return Number of free bytes that exist continuously.
*/
size_t yalloc_count_continuous(void * pool_);
/**
Queries the usable size of an allocated block.
@param pool The starting address of the initialized pool the allocation comes from.
@param p An address that was returned from yalloc_alloc() of the same pool.
@return Size of the memory block. This is the size passed to @ref yalloc_alloc() rounded up to 4.
*/
size_t yalloc_block_size(void * pool, void * p);
/**
Finds the first (in address order) allocation of a pool.
@param pool The starting address of an initialized pool.
@return Address of the allocation the lowest address inside the pool (this is
what @ref yalloc_alloc() returned), or \c NULL if there is no used block.
*/
void * yalloc_first_used(void * pool);
/**
Given a pointer to an allocation finds the next (in address order) used block of a pool.
@param pool The starting address of the initialized pool the allocation comes from.
@param p Pointer to an allocation in that pool, typically comes from a previous
call to @ref yalloc_first_used()
*/
void * yalloc_next_used(void * pool, void * p);
/**
Starts defragmentation for a pool.
Allocations will stay where they are. But the pool is put in the "defagmenting"
state (see @ref yalloc_defrag_in_progress()).
The pool must not be in the "defragmenting" state when this function is called.
The pool is put into the "defragmenting" state by this function.
@param pool The starting address of an initialized pool.
*/
void yalloc_defrag_start(void * pool);
/**
Returns the address that an allocation will have after @ref yalloc_defrag_commit() is called.
The pool must be in the "defragmenting" state when this function is called.
@param pool The starting address of the initialized pool the allocation comes from.
@param p Pointer to an allocation in that pool.
@return The address the alloation will have after @ref yalloc_defrag_commit() is called.
*/
void * yalloc_defrag_address(void * pool, void * p);
/**
Finishes the defragmentation.
The content of all allocations in the pool will be moved to the address that
was reported by @ref yalloc_defrag_address(). The pool will then have only one
free block. This means that an <tt>yalloc_alloc(pool, yalloc_count_free(pool))</tt>
will succeed.
The pool must be in the "defragmenting" state when this function is called. The
pool is put back to normal state by this function.
@param pool The starting address of an initialized pool.
*/
void yalloc_defrag_commit(void * pool);
/**
Tells if the pool is in the "defragmenting" state (after a @ref yalloc_defrag_start() and before a @ref yalloc_defrag_commit()).
@param pool The starting address of an initialized pool.
@return Nonzero if the pool is currently in the "defragmenting" state.
*/
int yalloc_defrag_in_progress(void * pool);
/**
Helper function that dumps the state of the pool to stdout.
This function is only available if build with <tt>yalloc_dump.c</tt>. This
function only exists for debugging purposes and can be ignored by normal users
that are not interested in the internal structure of the implementation.
@param pool The starting address of an initialized pool.
@param name A string that is used as "Title" for the output.
*/
void yalloc_dump(void * pool, char * name);
#endif // YALLOC_H

View File

@ -1,39 +0,0 @@
#include "yalloc_internals.h"
#include <stdio.h>
static void printOffset(void * pool, char * name, uint16_t offset)
{
if (isNil(offset))
printf(" %s: nil\n", name);
else
printf(" %s: %td\n", name, (char*)HDR_PTR(offset) - (char*)pool);
}
void yalloc_dump(void * pool, char * name)
{
printf("---- %s ----\n", name);
Header * cur = (Header*)pool;
for (;;)
{
printf(isFree(cur) ? "%td: free @%p\n" : "%td: used @%p\n", (char*)cur - (char*)pool, cur);
printOffset(pool, cur == pool ? "first free" : "prev", cur->prev);
printOffset(pool, "next", cur->next);
if (isFree(cur))
{
printOffset(pool, "prevFree", cur[1].prev);
printOffset(pool, "nextFree", cur[1].next);
}
else
printf(" payload includes padding: %i\n", isPadded(cur));
if (isNil(cur->next))
break;
printf(" %td bytes payload\n", (char*)HDR_PTR(cur->next) - (char*)cur - sizeof(Header));
cur = HDR_PTR(cur->next);
}
fflush(stdout);
}

View File

@ -1,59 +0,0 @@
#ifndef YALLOC_INTERNALS_H
#define YALLOC_INTERNALS_H
#include <stdint.h>
typedef struct
{
uint32_t prev; // low bit set if free
uint32_t next; // for used blocks: low bit set if unused header at the end
} Header;
// NOTE: We have 32bit aligned data and 16bit offsets where the lowest bit is used as flag. So we remove the low bit and shift by 1 to address 128k bytes with the 15bit significant offset bits.
#define NIL 0xFFFFFFFEu
// return Header-address for a prev/next
#define HDR_PTR(offset) ((Header*)((char*)pool + (((offset) & NIL)<<1)))
// return a prev/next for a Header-address
#define HDR_OFFSET(blockPtr) ((uint32_t)(((char*)blockPtr - (char*)pool) >> 1))
#ifndef YALLOC_INTERNAL_VALIDATE
# ifdef NDEBUG
# define YALLOC_INTERNAL_VALIDATE 0
# else
# define YALLOC_INTERNAL_VALIDATE 1
#endif
#endif
/*
internal_assert() is used in some places to check internal expections.
Activate this if you modify the code to detect problems as early as possible.
In other cases this should be deactivated.
*/
#if 0
#define internal_assert assert
#else
#define internal_assert(condition)((void) 0)
#endif
// detects offsets that point nowhere
static inline int isNil(uint32_t offset)
{
return (offset | 1) == 0xFFFFFFFF;
}
static inline int isFree(Header * hdr)
{
return hdr->prev & 1;
}
static inline int isPadded(Header * hdr)
{
return hdr->next & 1;
}
#endif // YALLOC_INTERNALS_H

View File

@ -32,7 +32,7 @@ GLdc uses CMake for its build system, it currently ships with two "backends":
- kospvr - This is the hardware-accelerated Dreamcast backend
- software - This is a stub software rasterizer used for testing testing and debugging
To compile for Dreamcast, you'll want to do something like the following:
To compile a Dreamcast debug build, you'll want to do something like the following:
```
mkdir dcbuild
@ -41,6 +41,11 @@ cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/Dreamcast.cmake -G "Unix Makefiles" .
make
```
For a release build, replace the cmake line with with the following:
```
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/Dreamcast.cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release ..
```
You will need KallistiOS compiled and configured (e.g. the KOS_BASE environment
variable must be set)

View File

@ -4,15 +4,6 @@
#include <assert.h>
#include <stdio.h>
#if defined(__APPLE__) || defined(__WIN32__)
/* Linux + Kos define this, OSX does not, so just use malloc there */
static inline void* memalign(size_t alignment, size_t size) {
return malloc(size);
}
#else
#include <malloc.h>
#endif
#ifdef _arch_dreamcast
#include "../GL/private.h"
#else
@ -21,112 +12,45 @@ static inline void* memalign(size_t alignment, size_t size) {
#include "aligned_vector.h"
void aligned_vector_init(AlignedVector* vector, unsigned int element_size) {
vector->size = vector->capacity = 0;
vector->element_size = element_size;
extern inline void* aligned_vector_resize(AlignedVector* vector, const uint32_t element_count);
extern inline void* aligned_vector_extend(AlignedVector* vector, const uint32_t additional_count);
extern inline void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count);
extern inline void* aligned_vector_push_back(AlignedVector* vector, const void* objs, uint32_t count);
void aligned_vector_init(AlignedVector* vector, uint32_t element_size) {
/* Now initialize the header*/
AlignedVectorHeader* const hdr = &vector->hdr;
hdr->size = 0;
hdr->capacity = ALIGNED_VECTOR_CHUNK_SIZE;
hdr->element_size = element_size;
vector->data = NULL;
/* Reserve some initial capacity */
aligned_vector_reserve(vector, ALIGNED_VECTOR_CHUNK_SIZE);
}
static inline unsigned int round_to_chunk_size(unsigned int val) {
const unsigned int n = val;
const unsigned int m = ALIGNED_VECTOR_CHUNK_SIZE;
return ((n + m - 1) / m) * m;
}
void aligned_vector_reserve(AlignedVector* vector, unsigned int element_count) {
if(element_count == 0) {
return;
}
if(element_count <= vector->capacity) {
return;
}
unsigned int original_byte_size = vector->size * vector->element_size;
/* We overallocate so that we don't make small allocations during push backs */
element_count = round_to_chunk_size(element_count);
unsigned int new_byte_size = element_count * vector->element_size;
unsigned char* original_data = vector->data;
vector->data = (unsigned char*) memalign(0x20, new_byte_size);
assert(vector->data);
if(original_data) {
FASTCPY(vector->data, original_data, original_byte_size);
free(original_data);
}
vector->capacity = element_count;
}
void* aligned_vector_push_back(AlignedVector* vector, const void* objs, unsigned int count) {
/* Resize enough room */
assert(count);
assert(vector->element_size);
unsigned int initial_size = vector->size;
aligned_vector_resize(vector, vector->size + count);
assert(vector->size == initial_size + count);
unsigned char* dest = vector->data + (vector->element_size * initial_size);
/* Copy the objects in */
FASTCPY(dest, objs, vector->element_size * count);
return dest;
}
void* aligned_vector_resize(AlignedVector* vector, const unsigned int element_count) {
unsigned int previousCount = vector->size;
/* Don't change memory when resizing downwards, just change the size */
if(element_count <= vector->size) {
vector->size = element_count;
return NULL;
}
if(vector->capacity < element_count) {
aligned_vector_reserve(vector, element_count);
}
vector->size = element_count;
if(previousCount < vector->size) {
return aligned_vector_at(vector, previousCount);
} else {
return NULL;
}
}
void* aligned_vector_extend(AlignedVector* vector, const unsigned int additional_count) {
const unsigned int current = vector->size;
aligned_vector_resize(vector, vector->size + additional_count);
return aligned_vector_at(vector, current);
/* Reserve some initial capacity. This will do the allocation but not set up the header */
void* ptr = aligned_vector_reserve(vector, ALIGNED_VECTOR_CHUNK_SIZE);
assert(ptr);
(void) ptr;
}
void aligned_vector_shrink_to_fit(AlignedVector* vector) {
if(vector->size == 0) {
AlignedVectorHeader* const hdr = &vector->hdr;
if(hdr->size == 0) {
uint32_t element_size = hdr->element_size;
free(vector->data);
/* Reallocate the header */
vector->data = NULL;
vector->capacity = 0;
hdr->size = hdr->capacity = 0;
hdr->element_size = element_size;
} else {
unsigned int new_byte_size = vector->size * vector->element_size;
unsigned char* original_data = vector->data;
uint32_t new_byte_size = (hdr->size * hdr->element_size);
uint8_t* original_data = vector->data;
vector->data = (unsigned char*) memalign(0x20, new_byte_size);
if(original_data) {
FASTCPY(vector->data, original_data, new_byte_size);
free(original_data);
}
vector->capacity = vector->size;
hdr->capacity = hdr->size;
}
}

View File

@ -2,36 +2,219 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__APPLE__) || defined(__WIN32__)
/* Linux + Kos define this, OSX does not, so just use malloc there */
static inline void* memalign(size_t alignment, size_t size) {
(void) alignment;
return malloc(size);
}
#else
#include <malloc.h>
#endif
#ifdef __cplusplus
#define AV_FORCE_INLINE static inline
#else
#define AV_NO_INSTRUMENT inline __attribute__((no_instrument_function))
#define AV_INLINE_DEBUG AV_NO_INSTRUMENT __attribute__((always_inline))
#define AV_FORCE_INLINE static AV_INLINE_DEBUG
#endif
#ifdef __DREAMCAST__
#include <kos/string.h>
AV_FORCE_INLINE void *AV_MEMCPY4(void *dest, const void *src, size_t len)
{
if(!len)
{
return dest;
}
const uint8_t *s = (uint8_t *)src;
uint8_t *d = (uint8_t *)dest;
uint32_t diff = (uint32_t)d - (uint32_t)(s + 1); // extra offset because input gets incremented before output is calculated
// Underflow would be like adding a negative offset
// Can use 'd' as a scratch reg now
asm volatile (
"clrs\n" // Align for parallelism (CO) - SH4a use "stc SR, Rn" instead with a dummy Rn
".align 2\n"
"0:\n\t"
"dt %[size]\n\t" // (--len) ? 0 -> T : 1 -> T (EX 1)
"mov.b @%[in]+, %[scratch]\n\t" // scratch = *(s++) (LS 1/2)
"bf.s 0b\n\t" // while(s != nexts) aka while(!T) (BR 1/2)
" mov.b %[scratch], @(%[offset], %[in])\n" // *(datatype_of_s*) ((char*)s + diff) = scratch, where src + diff = dest (LS 1)
: [in] "+&r" ((uint32_t)s), [scratch] "=&r" ((uint32_t)d), [size] "+&r" (len) // outputs
: [offset] "z" (diff) // inputs
: "t", "memory" // clobbers
);
return dest;
}
#else
#define AV_MEMCPY4 memcpy
#endif
typedef struct {
unsigned int size;
unsigned int capacity;
unsigned char* data;
unsigned int element_size;
uint32_t size;
uint32_t capacity;
uint32_t element_size;
} __attribute__((aligned(32))) AlignedVectorHeader;
typedef struct {
AlignedVectorHeader hdr;
uint8_t* data;
} AlignedVector;
#define ALIGNED_VECTOR_CHUNK_SIZE 256u
void aligned_vector_init(AlignedVector* vector, unsigned int element_size);
void aligned_vector_reserve(AlignedVector* vector, unsigned int element_count);
void* aligned_vector_push_back(AlignedVector* vector, const void* objs, unsigned int count);
void* aligned_vector_resize(AlignedVector* vector, const unsigned int element_count);
static inline void* aligned_vector_at(const AlignedVector* vector, const unsigned int index) {
assert(index < vector->size);
return &vector->data[index * vector->element_size];
#define ROUND_TO_CHUNK_SIZE(v) \
((((v) + ALIGNED_VECTOR_CHUNK_SIZE - 1) / ALIGNED_VECTOR_CHUNK_SIZE) * ALIGNED_VECTOR_CHUNK_SIZE)
void aligned_vector_init(AlignedVector* vector, uint32_t element_size);
AV_FORCE_INLINE void* aligned_vector_at(const AlignedVector* vector, const uint32_t index) {
const AlignedVectorHeader* hdr = &vector->hdr;
assert(index < hdr->size);
return vector->data + (index * hdr->element_size);
}
void* aligned_vector_extend(AlignedVector* vector, const unsigned int additional_count);
static inline void aligned_vector_clear(AlignedVector* vector){
vector->size = 0;
AV_FORCE_INLINE void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count) {
AlignedVectorHeader* hdr = &vector->hdr;
if(element_count < hdr->capacity) {
return aligned_vector_at(vector, element_count);
}
uint32_t original_byte_size = (hdr->size * hdr->element_size);
/* We overallocate so that we don't make small allocations during push backs */
element_count = ROUND_TO_CHUNK_SIZE(element_count);
uint32_t new_byte_size = (element_count * hdr->element_size);
uint8_t* original_data = vector->data;
vector->data = (uint8_t*) memalign(0x20, new_byte_size);
assert(vector->data);
AV_MEMCPY4(vector->data, original_data, original_byte_size);
free(original_data);
hdr->capacity = element_count;
return vector->data + original_byte_size;
}
AV_FORCE_INLINE AlignedVectorHeader* aligned_vector_header(const AlignedVector* vector) {
return (AlignedVectorHeader*) &vector->hdr;
}
AV_FORCE_INLINE uint32_t aligned_vector_size(const AlignedVector* vector) {
const AlignedVectorHeader* hdr = &vector->hdr;
return hdr->size;
}
AV_FORCE_INLINE uint32_t aligned_vector_capacity(const AlignedVector* vector) {
const AlignedVectorHeader* hdr = &vector->hdr;
return hdr->capacity;
}
AV_FORCE_INLINE void* aligned_vector_front(const AlignedVector* vector) {
return vector->data;
}
#define av_assert(x) \
do {\
if(!(x)) {\
fprintf(stderr, "Assertion failed at %s:%d\n", __FILE__, __LINE__);\
exit(1);\
}\
} while(0); \
/* Resizes the array and returns a pointer to the first new element (if upsizing) or NULL (if downsizing) */
AV_FORCE_INLINE void* aligned_vector_resize(AlignedVector* vector, const uint32_t element_count) {
void* ret = NULL;
AlignedVectorHeader* hdr = &vector->hdr;
uint32_t previous_count = hdr->size;
if(hdr->capacity <= element_count) {
/* If we didn't have capacity, increase capacity (slow) */
aligned_vector_reserve(vector, element_count);
hdr->size = element_count;
ret = aligned_vector_at(vector, previous_count);
av_assert(hdr->size == element_count);
av_assert(hdr->size <= hdr->capacity);
} else if(previous_count < element_count) {
/* So we grew, but had the capacity, just get a pointer to
* where we were */
hdr->size = element_count;
av_assert(hdr->size < hdr->capacity);
ret = aligned_vector_at(vector, previous_count);
} else if(hdr->size != element_count) {
hdr->size = element_count;
av_assert(hdr->size < hdr->capacity);
}
return ret;
}
AV_FORCE_INLINE void* aligned_vector_push_back(AlignedVector* vector, const void* objs, uint32_t count) {
/* Resize enough room */
AlignedVectorHeader* hdr = &vector->hdr;
assert(count);
assert(hdr->element_size);
#ifndef NDEBUG
uint32_t element_size = hdr->element_size;
uint32_t initial_size = hdr->size;
#endif
uint8_t* dest = (uint8_t*) aligned_vector_resize(vector, hdr->size + count);
assert(dest);
/* Copy the objects in */
AV_MEMCPY4(dest, objs, hdr->element_size * count);
assert(hdr->element_size == element_size);
assert(hdr->size == initial_size + count);
return dest;
}
AV_FORCE_INLINE void* aligned_vector_extend(AlignedVector* vector, const uint32_t additional_count) {
AlignedVectorHeader* hdr = &vector->hdr;
void* ret = aligned_vector_resize(vector, hdr->size + additional_count);
assert(ret); // Should always return something
return ret;
}
AV_FORCE_INLINE void aligned_vector_clear(AlignedVector* vector){
AlignedVectorHeader* hdr = &vector->hdr;
hdr->size = 0;
}
void aligned_vector_shrink_to_fit(AlignedVector* vector);
void aligned_vector_cleanup(AlignedVector* vector);
static inline void* aligned_vector_back(AlignedVector* vector){
return aligned_vector_at(vector, vector->size - 1);
AV_FORCE_INLINE void* aligned_vector_back(AlignedVector* vector){
AlignedVectorHeader* hdr = &vector->hdr;
return aligned_vector_at(vector, hdr->size ? hdr->size - 1 : 0);
}
#ifdef __cplusplus

View File

@ -68,7 +68,6 @@ void* named_array_reserve(NamedArray* array, unsigned int id) {
void named_array_release(NamedArray* array, unsigned int new_id) {
unsigned int i = new_id / 8;
unsigned int j = new_id % 8;
array->used_markers[i] &= (unsigned char) ~(1 << j);
}

View File

@ -19,6 +19,10 @@ __BEGIN_DECLS
#include <math.h>
#if __STDCPP_FLOAT16_T__
#include <stdfloat>
#endif
/* Primitive Types taken from GL for compatability */
/* Not all types are implemented in Open GL DC V.1.0 */
#define GL_POINTS 0x0000
@ -36,9 +40,20 @@ __BEGIN_DECLS
#define GL_CW 0x0900
#define GL_CCW 0x0901
#define GL_NONE 0
#define GL_FRONT_LEFT 0x0400
#define GL_FRONT_RIGHT 0x0401
#define GL_BACK_LEFT 0x0402
#define GL_BACK_RIGHT 0x0403
#define GL_FRONT 0x0404
#define GL_BACK 0x0405
#define GL_LEFT 0x0406
#define GL_RIGHT 0x0407
#define GL_FRONT_AND_BACK 0x0408
#define GL_AUX0 0x0409
#define GL_AUX1 0x040A
#define GL_AUX2 0x040B
#define GL_AUX3 0x040C
#define GL_CULL_FACE 0x0B44
#define GL_CULL_FACE_MODE 0x0B45
#define GL_FRONT_FACE 0x0B46
@ -47,6 +62,12 @@ __BEGIN_DECLS
#define GL_SCISSOR_TEST 0x0008 /* capability bit */
#define GL_SCISSOR_BOX 0x0C10
/* Stencil actions */
#define GL_KEEP 0x1E00
#define GL_INCR 0x1E02
#define GL_DECR 0x1E03
#define GL_INVERT 0x150A
/* Matrix modes */
#define GL_MATRIX_MODE 0x0BA0
#define GL_MODELVIEW 0x1700
@ -178,6 +199,14 @@ __BEGIN_DECLS
#define GL_SCISSOR_BIT 0x00080000
#define GL_ALL_ATTRIB_BITS 0x000FFFFF
/* Clip planes */
#define GL_CLIP_PLANE0 0x3000
#define GL_CLIP_PLANE1 0x3001
#define GL_CLIP_PLANE2 0x3002
#define GL_CLIP_PLANE3 0x3003
#define GL_CLIP_PLANE4 0x3004
#define GL_CLIP_PLANE5 0x3005
/* Fog */
#define GL_FOG 0x0004 /* capability bit */
#define GL_FOG_MODE 0x0B65
@ -280,12 +309,13 @@ __BEGIN_DECLS
#define GL_UNSIGNED_INT 0x1405
#define GL_FLOAT 0x1406
#define GL_DOUBLE 0x140A
#define GL_HALF_FLOAT 0x140B
#define GL_2_BYTES 0x1407
#define GL_3_BYTES 0x1408
#define GL_4_BYTES 0x1409
/* ErrorCode */
#define GL_NO_ERROR 0
#define GL_NO_ERROR ((GLenum) 0)
#define GL_INVALID_ENUM 0x0500
#define GL_INVALID_VALUE 0x0501
#define GL_INVALID_OPERATION 0x0502
@ -334,7 +364,7 @@ __BEGIN_DECLS
#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
#define GL_COLOR_INDEX 0x1900
@ -346,6 +376,32 @@ __BEGIN_DECLS
#define GL_RGBA 0x1908
#define GL_LUMINANCE 0x1909
#define GL_LUMINANCE_ALPHA 0x190A
#define GL_R3_G3_B2 0x2A10
#define GL_ALPHA4 0x803B
#define GL_ALPHA8 0x803C
#define GL_ALPHA12 0x803D
#define GL_ALPHA16 0x803E
#define GL_LUMINANCE4 0x803F
#define GL_LUMINANCE8 0x8040
#define GL_LUMINANCE12 0x8041
#define GL_LUMINANCE16 0x8042
#define GL_LUMINANCE4_ALPHA4 0x8043
#define GL_LUMINANCE6_ALPHA2 0x8044
#define GL_LUMINANCE8_ALPHA8 0x8045
#define GL_LUMINANCE12_ALPHA4 0x8046
#define GL_LUMINANCE12_ALPHA12 0x8047
#define GL_LUMINANCE16_ALPHA16 0x8048
#define GL_INTENSITY4 0x804A
#define GL_INTENSITY8 0x804B
#define GL_INTENSITY12 0x804C
#define GL_INTENSITY16 0x804D
#define GL_BGR 0x80E0
#define GL_BGRA 0x80E1
#define GL_INTENSITY 0x8049
#define GL_RGB4 0x804F
@ -362,6 +418,14 @@ __BEGIN_DECLS
#define GL_RGBA12 0x805A
#define GL_RGBA16 0x805B
#define GL_R8 0x8229
#define GL_RG8 0x822B
#define GL_RG 0x8227
#define GL_R16 0x822A
#define GL_RG16 0x822C
#define GL_COMPRESSED_RED 0x8225
#define GL_COMPRESSED_RG 0x8226
/* Polygons */
#define GL_POINT 0x1B00
#define GL_LINE 0x1B01
@ -395,22 +459,44 @@ __BEGIN_DECLS
#define GLsizei unsigned int
#define GLfixed const unsigned int
#define GLclampf float
#define GLclampd float
#define GLubyte unsigned char
#define GLbitfield unsigned int
#define GLboolean unsigned char
#define GL_FALSE 0
#define GL_TRUE 1
#if __STDCPP_FLOAT16_T__
#define GLhalf std::float16_t
#else
#define GLhalf unsigned short
#endif
/* Stubs for portability */
#define GL_LINE_SMOOTH 0x0B20
#define GL_ALPHA_TEST 0x0BC0
#define GL_STENCIL_TEST 0x0B90
#define GL_STENCIL_WRITEMASK 0x0B98
#define GL_INDEX_WRITEMASK 0x0C21
#define GL_COLOR_WRITEMASK 0x0C23
#define GL_UNPACK_SWAP_BYTES 0x0CF0
#define GL_UNPACK_LSB_FIRST 0x0CF1
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#define GL_UNPACK_SKIP_ROWS 0x0CF3
#define GL_UNPACK_SKIP_PIXELS 0x0CF4
#define GL_UNPACK_ALIGNMENT 0x0CF5
#define GL_PACK_SWAP_BYTES 0x0D00
#define GL_PACK_LSB_FIRST 0x0D01
#define GL_PACK_ROW_LENGTH 0x0D02
#define GL_PACK_SKIP_ROWS 0x0D03
#define GL_PACK_SKIP_PIXELS 0x0D04
#define GL_PACK_ALIGNMENT 0x0D05
#define GLAPI extern
#define APIENTRY
GLAPI void APIENTRY glFlush();
GLAPI void APIENTRY glFinish();
GLAPI void APIENTRY glFlush(void);
GLAPI void APIENTRY glFinish(void);
/* Start Submission of Primitive Data */
/* Currently Supported Primitive Types:
@ -422,15 +508,18 @@ GLAPI void APIENTRY glFinish();
GLAPI void APIENTRY glBegin(GLenum mode);
/* Finish Submission of Primitive Data */
GLAPI void APIENTRY glEnd();
GLAPI void APIENTRY glEnd(void);
/* Primitive Texture Coordinate Submission */
GLAPI void APIENTRY glTexCoord1f(GLfloat u);
GLAPI void APIENTRY glTexCoord1fv(const GLfloat *u);
GLAPI void APIENTRY glTexCoord2f(GLfloat u, GLfloat v);
GLAPI void APIENTRY glTexCoord2fv(const GLfloat *uv);
/* Primitive Color Submission */
GLAPI void APIENTRY glColor1ui(GLuint argb);
GLAPI void APIENTRY glColor4ub(GLubyte r, GLubyte g, GLubyte b, GLubyte a);
GLAPI void APIENTRY glColor4ubv(const GLubyte *v);
GLAPI void APIENTRY glColor3f(GLfloat r, GLfloat g, GLfloat b);
GLAPI void APIENTRY glColor3ub(GLubyte r, GLubyte g, GLubyte b);
GLAPI void APIENTRY glColor3ubv(const GLubyte *v);
@ -511,6 +600,7 @@ GLAPI void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor);
/* Texturing */
GLAPI void APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param);
GLAPI void APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param);
GLAPI void APIENTRY glTexEnvi(GLenum target, GLenum pname, GLint param);
GLAPI void APIENTRY glTexEnvf(GLenum target, GLenum pname, GLfloat param);
@ -584,15 +674,15 @@ GLAPI void APIENTRY glDisableClientState(GLenum cap);
GLAPI void APIENTRY glMatrixMode(GLenum mode);
GLAPI void APIENTRY glLoadIdentity();
GLAPI void APIENTRY glLoadIdentity(void);
GLAPI void APIENTRY glLoadMatrixf(const GLfloat *m);
GLAPI void APIENTRY glLoadTransposeMatrixf(const GLfloat *m);
GLAPI void APIENTRY glMultMatrixf(const GLfloat *m);
GLAPI void APIENTRY glMultTransposeMatrixf(const GLfloat *m);
GLAPI void APIENTRY glPushMatrix();
GLAPI void APIENTRY glPopMatrix();
GLAPI void APIENTRY glPushMatrix(void);
GLAPI void APIENTRY glPopMatrix(void);
GLAPI void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z);
#define glTranslated glTranslatef
@ -620,6 +710,7 @@ GLAPI void APIENTRY glFrustum(GLfloat left, GLfloat right,
/* Fog Functions - client must enable GL_FOG for this to take effect */
GLAPI void APIENTRY glFogi(GLenum pname, GLint param);
GLAPI void APIENTRY glFogf(GLenum pname, GLfloat param);
GLAPI void APIENTRY glFogiv(GLenum pname, const GLint* params);
GLAPI void APIENTRY glFogfv(GLenum pname, const GLfloat *params);
/* Lighting Functions - client must enable GL_LIGHTING for this to take effect */
@ -653,10 +744,15 @@ GLAPI GLenum APIENTRY glGetError(void);
/* Non Operational Stubs for portability */
GLAPI void APIENTRY glAlphaFunc(GLenum func, GLclampf ref);
GLAPI void APIENTRY glLineWidth(GLfloat width);
GLAPI void APIENTRY glPolygonMode(GLenum face, GLenum mode);
GLAPI void APIENTRY glPolygonOffset(GLfloat factor, GLfloat units);
GLAPI void APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint * params);
GLAPI void APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params);
GLAPI void APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint *params);
GLAPI void APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
GLAPI void APIENTRY glPixelStorei(GLenum pname, GLint param);
GLAPI void APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask);
GLAPI void APIENTRY glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
GLAPI void APIENTRY glGetTexImage(GLenum tex, GLint lod, GLenum format, GLenum type, GLvoid* img);
__END_DECLS

View File

@ -130,7 +130,7 @@ GLAPI void APIENTRY glGenFramebuffersEXT(GLsizei n, GLuint* framebuffers);
GLAPI void APIENTRY glDeleteFramebuffersEXT(GLsizei n, const GLuint* framebuffers);
GLAPI void APIENTRY glBindFramebufferEXT(GLenum target, GLuint framebuffer);
GLAPI void APIENTRY glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
GLAPI void APIENTRY glGenerateMipmapEXT(GLenum target);
GLAPI void APIENTRY glGenerateMipmap(GLenum target);
GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT(GLenum target);
GLAPI GLboolean APIENTRY glIsFramebufferEXT(GLuint framebuffer);
@ -161,6 +161,22 @@ GLAPI void APIENTRY glGetColorTableEXT(GLenum target, GLenum format, GLenum type
GLAPI void APIENTRY glGetColorTableParameterivEXT(GLenum target, GLenum pname, GLint *params);
GLAPI void APIENTRY glGetColorTableParameterfvEXT(GLenum target, GLenum pname, GLfloat *params);
/* ext OES_compressed_paletted_texture */
/* PixelInternalFormat */
//Ozzy: used MesaGL definitions please adjust if it causes probs.
#define GL_PALETTE4_RGB8_OES 0x8B90
#define GL_PALETTE4_RGBA8_OES 0x8B91
#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
#define GL_PALETTE4_RGBA4_OES 0x8B93
#define GL_PALETTE4_RGB5_A1_OES 0x8B94
#define GL_PALETTE8_RGB8_OES 0x8B95
#define GL_PALETTE8_RGBA8_OES 0x8B96
#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
#define GL_PALETTE8_RGBA4_OES 0x8B98
#define GL_PALETTE8_RGB5_A1_OES 0x8B99
/* Loads VQ compressed texture from SH4 RAM into PVR VRAM */
/* internalformat must be one of the following constants:
GL_UNSIGNED_SHORT_5_6_5_VQ
@ -187,7 +203,7 @@ GLAPI void APIENTRY glCompressedTexImage2DARB(GLenum target,
#define glClientActiveTexture glClientActiveTextureARB
#define glMultiTexCoord2f glMultiTexCoord2fARB
#define glGenerateMipmap glGenerateMipmapEXT
#define glGenerateMipmapEXT glGenerateMipmap
#define glCompressedTexImage2D glCompressedTexImage2DARB
#ifndef GL_VERSION_1_4
@ -195,7 +211,7 @@ GLAPI void APIENTRY glCompressedTexImage2DARB(GLenum target,
#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
#define GL_TEXTURE_LOD_BIAS 0x8501
#define GL_MAX_TEXTURE_LOD_BIAS_DEFAULT 7
#define GL_KOS_INTERNAL_DEFAULT_MIPMAP_LOD_BIAS -4
#define GL_KOS_INTERNAL_DEFAULT_MIPMAP_LOD_BIAS 4
#endif
#ifndef GL_EXT_texture_lod_bias

View File

@ -35,8 +35,6 @@ extern const char* GLDC_VERSION;
#define GL_NEARZ_CLIPPING_KOS 0xEEFA
#define GL_UNSIGNED_BYTE_TWID_KOS 0xEEFB
/* Initialize the GL pipeline. GL will initialize the PVR. */
GLAPI void APIENTRY glKosInit();
@ -56,6 +54,14 @@ typedef struct {
GLuint initial_tr_capacity;
GLuint initial_pt_capacity;
GLuint initial_immediate_capacity;
/* Default: True
*
* Whether glTexImage should automatically twiddle textures
* if the internal format is a generic format (e.g. GL_RGB).
* this is the same as calling glEnable(GL_TEXTURE_TWIDDLE_KOS)
* on boot */
GLboolean texture_twiddle;
} GLdcConfig;
@ -86,6 +92,7 @@ GLAPI void APIENTRY glKosInitConfig(GLdcConfig* config);
*/
GLAPI void APIENTRY glKosInitEx(GLdcConfig* config);
GLAPI void APIENTRY glKosSwapBuffers();
GLAPI void APIENTRY glKosShutdown();
/*
* CUSTOM EXTENSION multiple_shared_palette_KOS
@ -106,20 +113,106 @@ GLAPI void APIENTRY glKosSwapBuffers();
* by default textures use shared palette 0.
*/
#define GL_SHARED_TEXTURE_PALETTE_0_KOS 0xEEFC
#define GL_SHARED_TEXTURE_PALETTE_1_KOS 0xEEFD
#define GL_SHARED_TEXTURE_PALETTE_2_KOS 0xEEFE
#define GL_SHARED_TEXTURE_PALETTE_3_KOS 0xEEFF
#define GL_SHARED_TEXTURE_PALETTE_4_KOS 0xEF00
#define GL_SHARED_TEXTURE_PALETTE_5_KOS 0xEF01
#define GL_SHARED_TEXTURE_PALETTE_6_KOS 0xEF02
#define GL_SHARED_TEXTURE_PALETTE_7_KOS 0xEF03
#define GL_SHARED_TEXTURE_PALETTE_8_KOS 0xEF04
#define GL_SHARED_TEXTURE_PALETTE_9_KOS 0xEF05
#define GL_SHARED_TEXTURE_PALETTE_10_KOS 0xEF06
#define GL_SHARED_TEXTURE_PALETTE_11_KOS 0xEF07
#define GL_SHARED_TEXTURE_PALETTE_12_KOS 0xEF08
#define GL_SHARED_TEXTURE_PALETTE_13_KOS 0xEF09
#define GL_SHARED_TEXTURE_PALETTE_14_KOS 0xEF0A
#define GL_SHARED_TEXTURE_PALETTE_15_KOS 0xEF0B
#define GL_SHARED_TEXTURE_PALETTE_16_KOS 0xEF0C
#define GL_SHARED_TEXTURE_PALETTE_17_KOS 0xEF0D
#define GL_SHARED_TEXTURE_PALETTE_18_KOS 0xEF0E
#define GL_SHARED_TEXTURE_PALETTE_19_KOS 0xEF0F
#define GL_SHARED_TEXTURE_PALETTE_20_KOS 0xEF10
#define GL_SHARED_TEXTURE_PALETTE_21_KOS 0xEF11
#define GL_SHARED_TEXTURE_PALETTE_22_KOS 0xEF12
#define GL_SHARED_TEXTURE_PALETTE_23_KOS 0xEF13
#define GL_SHARED_TEXTURE_PALETTE_24_KOS 0xEF14
#define GL_SHARED_TEXTURE_PALETTE_25_KOS 0xEF15
#define GL_SHARED_TEXTURE_PALETTE_26_KOS 0xEF16
#define GL_SHARED_TEXTURE_PALETTE_27_KOS 0xEF17
#define GL_SHARED_TEXTURE_PALETTE_28_KOS 0xEF18
#define GL_SHARED_TEXTURE_PALETTE_29_KOS 0xEF19
#define GL_SHARED_TEXTURE_PALETTE_30_KOS 0xEF1A
#define GL_SHARED_TEXTURE_PALETTE_31_KOS 0xEF1B
#define GL_SHARED_TEXTURE_PALETTE_32_KOS 0xEF1C
#define GL_SHARED_TEXTURE_PALETTE_33_KOS 0xEF1D
#define GL_SHARED_TEXTURE_PALETTE_34_KOS 0xEF1E
#define GL_SHARED_TEXTURE_PALETTE_35_KOS 0xEF1F
#define GL_SHARED_TEXTURE_PALETTE_36_KOS 0xEF20
#define GL_SHARED_TEXTURE_PALETTE_37_KOS 0xEF21
#define GL_SHARED_TEXTURE_PALETTE_38_KOS 0xEF22
#define GL_SHARED_TEXTURE_PALETTE_39_KOS 0xEF23
#define GL_SHARED_TEXTURE_PALETTE_40_KOS 0xEF24
#define GL_SHARED_TEXTURE_PALETTE_41_KOS 0xEF25
#define GL_SHARED_TEXTURE_PALETTE_42_KOS 0xEF26
#define GL_SHARED_TEXTURE_PALETTE_43_KOS 0xEF27
#define GL_SHARED_TEXTURE_PALETTE_44_KOS 0xEF28
#define GL_SHARED_TEXTURE_PALETTE_45_KOS 0xEF29
#define GL_SHARED_TEXTURE_PALETTE_46_KOS 0xEF2A
#define GL_SHARED_TEXTURE_PALETTE_47_KOS 0xEF2B
#define GL_SHARED_TEXTURE_PALETTE_48_KOS 0xEF2C
#define GL_SHARED_TEXTURE_PALETTE_49_KOS 0xEF2D
#define GL_SHARED_TEXTURE_PALETTE_50_KOS 0xEF2E
#define GL_SHARED_TEXTURE_PALETTE_51_KOS 0xEF2F
#define GL_SHARED_TEXTURE_PALETTE_52_KOS 0xEF30
#define GL_SHARED_TEXTURE_PALETTE_53_KOS 0xEF31
#define GL_SHARED_TEXTURE_PALETTE_54_KOS 0xEF32
#define GL_SHARED_TEXTURE_PALETTE_55_KOS 0xEF33
#define GL_SHARED_TEXTURE_PALETTE_56_KOS 0xEF34
#define GL_SHARED_TEXTURE_PALETTE_57_KOS 0xEF35
#define GL_SHARED_TEXTURE_PALETTE_58_KOS 0xEF36
#define GL_SHARED_TEXTURE_PALETTE_59_KOS 0xEF37
#define GL_SHARED_TEXTURE_PALETTE_60_KOS 0xEF38
#define GL_SHARED_TEXTURE_PALETTE_61_KOS 0xEF39
#define GL_SHARED_TEXTURE_PALETTE_62_KOS 0xEF3A
#define GL_SHARED_TEXTURE_PALETTE_63_KOS 0xEF3B
/* Pass to glTexParameteri to set the shared bank */
#define GL_SHARED_TEXTURE_BANK_KOS 0xEF00
#define GL_SHARED_TEXTURE_BANK_KOS 0xEF3C
/* Memory allocation extension (GL_KOS_texture_memory_management) */
GLAPI GLvoid APIENTRY glDefragmentTextureMemory_KOS(void);
#define GL_FREE_TEXTURE_MEMORY_KOS 0xEF01
#define GL_USED_TEXTURE_MEMORY_KOS 0xEF02
#define GL_FREE_CONTIGUOUS_TEXTURE_MEMORY_KOS 0xEF03
/* glGet extensions */
#define GL_FREE_TEXTURE_MEMORY_KOS 0xEF3D
#define GL_USED_TEXTURE_MEMORY_KOS 0xEF3E
#define GL_FREE_CONTIGUOUS_TEXTURE_MEMORY_KOS 0xEF3F
//for palette internal format (glfcConfig)
#define GL_RGB565_KOS 0xEF40
#define GL_ARGB4444_KOS 0xEF41
#define GL_ARGB1555_KOS 0xEF42
#define GL_RGB565_TWID_KOS 0xEF43
#define GL_ARGB4444_TWID_KOS 0xEF44
#define GL_ARGB1555_TWID_KOS 0xEF45
#define GL_COLOR_INDEX8_TWID_KOS 0xEF46
#define GL_COLOR_INDEX4_TWID_KOS 0xEF47
#define GL_RGB_TWID_KOS 0xEF48
#define GL_RGBA_TWID_KOS 0xEF49
/* glGet extensions */
#define GL_TEXTURE_INTERNAL_FORMAT_KOS 0xEF50
/* If enabled, will twiddle texture uploads where possible */
#define GL_TEXTURE_TWIDDLE_KOS 0xEF51
__END_DECLS

View File

@ -34,6 +34,11 @@ GLAPI void APIENTRY gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez,
GLfloat centerx, GLfloat centery, GLfloat centerz,
GLfloat upx, GLfloat upy, GLfloat upz);
/* generate mipmaps for any image provided by the user and then pass them to OpenGL */
GLAPI GLint APIENTRY gluBuild2DMipmaps(GLenum target, GLint internalFormat,
GLsizei width, GLsizei height,
GLenum format, GLenum type, const void *data);
GLAPI const GLubyte* APIENTRY gluErrorString(GLenum error);
__END_DECLS

View File

@ -1,36 +0,0 @@
# Manipulate the CFLAGS to look our *our* version of the library and includes
INC_DIR = $(abspath ../include)
LIB_DIR = $(abspath ../)
export CFLAGS := $(CFLAGS) -I $(INC_DIR)
export OBJEXTRA := $(LIB_DIR)/libGLdc.a
all:
$(KOS_MAKE) -C nehe02 all
$(KOS_MAKE) -C nehe02va all
$(KOS_MAKE) -C nehe02de all
$(KOS_MAKE) -C nehe03 all
$(KOS_MAKE) -C nehe04 all
$(KOS_MAKE) -C nehe05 all
$(KOS_MAKE) -C nehe06 all
$(KOS_MAKE) -C nehe06_vq all
$(KOS_MAKE) -C ortho2d all
$(KOS_MAKE) -C lerabot01 all
$(KOS_MAKE) -C zclip all
$(KOS_MAKE) -C zclip_triangle all
$(KOS_MAKE) -C zclip_trianglestrip all
$(KOS_MAKE) -C terrain all
$(KOS_MAKE) -C quadmark all
$(KOS_MAKE) -C trimark all
$(KOS_MAKE) -C multitexture_arrays all
$(KOS_MAKE) -C paletted all
$(KOS_MAKE) -C paletted_pcx all
$(KOS_MAKE) -C depth_funcs all
$(KOS_MAKE) -C polymark all
$(KOS_MAKE) -C polygon_offset all
$(KOS_MAKE) -C blend_test all
$(KOS_MAKE) -C mipmap all
$(KOS_MAKE) -C lights all
$(KOS_MAKE) -C depth_funcs_alpha_testing
$(KOS_MAKE) -C depth_funcs_ortho

View File

@ -1,29 +0,0 @@
TARGET = blend_test.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,9 +1,14 @@
/*
* This sample is to demonstrate a bug where rendering an unblended
* polygon, before a series of blended ones would result in no blended
* output and incorrect depth testing
* This sample demonstrates blending, and the importance of drawing order,
* depth testing and z-value.
* This is a merge of lerabot_blend_test and blend_test, with 1 added case,
* and with adapted/corrected explanation
*/
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -42,6 +47,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
void DrawQuad(const float* colour) {
glBegin(GL_QUADS);
@ -61,13 +83,13 @@ void DrawGLScene()
const float NONE [] = {0, 0, 0, 0};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
// LEFT UPPER SECTION
glLoadIdentity(); // Reset The View
glTranslatef(-4.0, 0, -10);
// LEFT SECTION
// This should draw 2 quad, a red first, then and overlapping blue one.
// This section draw both quad at the same Z value
glTranslatef(-4.0, 2.0, -10);
// This draws 2 quads, a red first, then an overlapping blue one.
// Both quads are drawn at the SAME z-value
// With depth test GL_LEQUAL, this means blending for the overlapping part
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
DrawQuad(RED);
@ -75,11 +97,24 @@ void DrawGLScene()
DrawQuad(BLUE);
glDisable(GL_BLEND);
// RIGHT UPPER SECTION
glTranslatef(4.0, 0, 0);
// This draws 2 quads, a red first, then an overlapping blue one.
// The blue quad has a LOWER z-value, so it is behind the red quad.
// With depth test GL_LEQUAL, the blue part is not considered for the overlapping part, so no blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
DrawQuad(RED);
glTranslatef(1.0, 0, -0.01);
DrawQuad(BLUE);
glDisable(GL_BLEND);
// RIGHT SECTION
// This should draw 2 quad, a red first, then and overlapping blue one.
// This section uses a HIGHER Z VALUE(0.01f), so the blue quad should be in FRONT of the red quad.
// LEFT DOWN SECTION
glLoadIdentity(); // Reset The View
glTranslatef(-4.0, -1.0, -10);
// This draws 2 quads, a red first, then an overlapping blue one.
// The blue quad has a HIGHER z-value, so it is in front the red quad.
// With depth test GL_LEQUAL, this means blending for the overlapping part
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
DrawQuad(RED);
@ -87,6 +122,20 @@ void DrawGLScene()
DrawQuad(BLUE);
glDisable(GL_BLEND);
// RIGHT DOWN SECTION
glTranslatef(4.0, 0.0, -0.01);
// This is basically the same as the RIGHT UPPER SECTION, except that the blue quad
// is drawn first.
// With depth test GL_LEQUAL, this means blending for the overlapping part
// <- the order of drawing is important for blending !
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTranslatef(1.0, 0.0, -0.01);
DrawQuad(BLUE);
glTranslatef(-1.0, 0.0, 0.01);
DrawQuad(RED);
glDisable(GL_BLEND);
glKosSwapBuffers();
}
@ -98,6 +147,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

446
samples/cubes/main.cpp Normal file
View File

@ -0,0 +1,446 @@
#include <cstdio>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#ifdef __DREAMCAST__
#include <kos.h>
float avgfps = -1;
#endif
#include "GL/gl.h"
#include "GL/glkos.h"
#include "GL/glu.h"
#include "GL/glext.h"
#define PI 3.14159265358979323846264338327950288f
#define RAD_TO_DEG 57.295779513082320876798154814105f
#define MAX_CUBES 350
float timeElapsed = 0.0f;
const float dt = 1.0f / 60.0f;
float angle = 0;
const float invAngle360 = 1.0f / 360.0f;
const float cameraDistance = 3.0f;
bool isDrawingArrays = false;
bool isBlendingEnabled = true;
bool isRunning = true;
typedef struct
{
GLubyte r;
GLubyte g;
GLubyte b;
GLubyte a;
} Color;
Color colors[] =
{
{255, 0, 0, 128},
{0, 255, 0, 128},
{0, 0, 255, 128},
{255, 255, 0, 128},
{255, 0, 255, 128},
{0, 255, 255, 128}
};
Color faceColors[24];
float cubeVertices[] =
{
// Front face
-1.0f, -1.0f, +1.0f, // vertex 0
+1.0f, -1.0f, +1.0f, // vertex 1
+1.0f, +1.0f, +1.0f, // vertex 2
-1.0f, +1.0f, +1.0f, // vertex 3
// Back face
-1.0f, -1.0f, -1.0f, // vertex 4
+1.0f, -1.0f, -1.0f, // vertex 5
+1.0f, +1.0f, -1.0f, // vertex 6
-1.0f, +1.0f, -1.0f, // vertex 7
// Top face
-1.0f, +1.0f, +1.0f, // vertex 8
+1.0f, +1.0f, +1.0f, // vertex 9
+1.0f, +1.0f, -1.0f, // vertex 10
-1.0f, +1.0f, -1.0f, // vertex 11
// Bottom face
-1.0f, -1.0f, +1.0f, // vertex 12
+1.0f, -1.0f, +1.0f, // vertex 13
+1.0f, -1.0f, -1.0f, // vertex 14
-1.0f, -1.0f, -1.0f, // vertex 15
// Right face
+1.0f, -1.0f, +1.0f, // vertex 16
+1.0f, -1.0f, -1.0f, // vertex 17
+1.0f, +1.0f, -1.0f, // vertex 18
+1.0f, +1.0f, +1.0f, // vertex 19
// Left face
-1.0f, -1.0f, +1.0f, // vertex 20
-1.0f, -1.0f, -1.0f, // vertex 21
-1.0f, +1.0f, -1.0f, // vertex 22
-1.0f, +1.0f, +1.0f // vertex 23
};
// Set up indices array
unsigned int cubeIndices[] =
{
// Front face
0, 1, 2, 3,
// Back face
4, 5, 6, 7,
// Top face
8, 9, 10, 11,
// Bottom face
12, 13, 14, 15,
// Right face
16, 17, 18, 19,
// Left face
20, 21, 22, 23
};
typedef struct
{
float r;
float x, y, z;
float vx, vy, vz;
} Cube;
Cube cubes[MAX_CUBES];
int numCubes = 0;
// Create a 4x4 identity matrix
float cubeTransformationMatrix[16] = { 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
void debugLog(const char* msg) {
#ifdef __DREAMCAST__
dbglog(DBG_KDEBUG, "%s\n", msg);
#else
printf("%s\n", msg);
#endif
}
void runningStats() {
#ifdef __DREAMCAST__
pvr_stats_t stats;
pvr_get_stats(&stats);
if (avgfps != -1)
avgfps = (avgfps + stats.frame_rate) * 0.5f;
else
avgfps = stats.frame_rate;
#endif
}
void avgStats() {
#ifdef __DREAMCAST__
dbglog(DBG_DEBUG, "Average frame rate: ~%f fps\n", avgfps);
#endif
}
void stats() {
#ifdef __DREAMCAST__
pvr_stats_t stats;
pvr_get_stats(&stats);
dbglog(DBG_DEBUG, "3D Stats: %d VBLs, current frame rate ~%f fps\n", stats.vbl_count, stats.frame_rate);
avgStats();
#endif
}
void addCube(float r, float x, float y, float z, float vx, float vy, float vz)
{
if (numCubes < MAX_CUBES) {
cubes[numCubes].r = r;
cubes[numCubes].x = x;
cubes[numCubes].y = y;
cubes[numCubes].z = z;
cubes[numCubes].vx = vx;
cubes[numCubes].vy = vy;
cubes[numCubes].vz = vz;
numCubes++;
}
}
void addCubeQuick(float x, float y, float z, float scale_factor)
{
addCube(0.5f * scale_factor, x, y, z, 0, 0, 0);
}
void updateCubes(float dt)
{
for (size_t i = 0; i < numCubes; i++)
{
Cube* cube = &cubes[i];
cube->x += cube->vx * dt;
cube->y += cube->vy * dt;
cube->z += cube->vz * dt;
if (cube->x < -3 || cube->x > +3) { cube->vx *= -1; }
if (cube->y < -3 || cube->y > +3) { cube->vy *= -1; }
if (cube->z < -3 || cube->z > +3) { cube->vz *= -1; }
}
}
void renderUnitCube()
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, faceColors);
if (isDrawingArrays) {
glDrawArrays(GL_QUADS, 0, 24);
}
else {
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, cubeIndices);
}
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
void renderCubes(float angle)
{
for (size_t i = 0; i < numCubes; i++) {
const float scale_factor = 0.05f + (i / (float)numCubes) * 0.35f;
Cube* cube = &cubes[i];
glPushMatrix(); // Save previous camera state
glMatrixMode(GL_MODELVIEW);
glTranslatef(cube->x, cube->y, cube->z);
glRotatef(angle, 1, 1, 1); // Rotate camera / object
glScalef(scale_factor, scale_factor, scale_factor); // Apply scale factor
renderUnitCube();
glPopMatrix(); // Restore previous camera state
}
}
float rnd(float Min, float Max)
{
return (Max - Min) * (float)rand() / (float)RAND_MAX + Min;
}
void initialize()
{
debugLog("Initialize video output");
glKosInit();
glClearDepth(1.0);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
if (isBlendingEnabled)
{
glEnable(GL_BLEND);
}
else
{
glDisable(GL_BLEND);
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glViewport(0, 0, 640, 480);
glClearColor(0.0f, 0.0f, 0.3f, 1.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set up colors (each face has a different color)
for (int i = 0; i < 6; i++)
{
faceColors[i * 4] = colors[i];
faceColors[i * 4 + 1] = colors[i];
faceColors[i * 4 + 2] = colors[i];
faceColors[i * 4 + 3] = colors[i];
}
}
void updateTimer()
{
timeElapsed += dt;
if (timeElapsed > 10.0f)
{
stats();
timeElapsed = 0.0f;
}
}
void updateLogic()
{
updateTimer();
const int fullRot = (int)(angle * invAngle360);
angle -= fullRot * 360.0f;
angle += 50.0f * dt;
const float zoomVal = __builtin_sinf(timeElapsed) * 5.0f;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Set up the camera position and orientation
float cameraPos[] = { 0.0f, 0.0f, cameraDistance };
float cameraTarget[] = { 0.0f, 0.0f, 0.0f };
float cameraUp[] = { 0.0f, 1.0f, 0.0f };
// Move the camera
gluLookAt(cameraPos[0], cameraPos[1], cameraPos[2],
cameraTarget[0], cameraTarget[1], cameraTarget[2],
cameraUp[0], cameraUp[1], cameraUp[2]);
glTranslatef(0.0f, 0.0f, -cameraDistance + zoomVal);
// Apply cube transformation (identity matrix)
glLoadIdentity();
updateCubes(dt);
renderCubes(angle);
// Reset ModelView matrix to remove camera transformation
float matrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
matrix[12] = 0.0f;
matrix[13] = 0.0f;
matrix[14] = 0.0f;
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(matrix);
}
void updateInput()
{
#ifdef __DREAMCAST__
static uint8_t prevButtons = 0;
maple_device_t* cont;
cont_state_t* state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if (cont)
{
state = (cont_state_t*)maple_dev_status(cont);
if (state && (state->buttons & CONT_START) && !(prevButtons & CONT_START))
{
isRunning = false;
}
if (state && (state->buttons & CONT_A) && !(prevButtons & CONT_A))
{
isDrawingArrays = !isDrawingArrays;
if (isDrawingArrays)
{
glClearColor(0.3f, 0.0f, 0.3f, 1.0f);
}
else
{
glClearColor(0.0f, 0.0f, 0.3f, 1.0f);
}
}
if (state && (state->buttons & CONT_B) && !(prevButtons & CONT_B))
{
isBlendingEnabled = !isBlendingEnabled;
if (isBlendingEnabled)
{
glEnable(GL_BLEND);
}
else
{
glDisable(GL_BLEND);
}
}
prevButtons = state->buttons;
}
#endif
}
void swapBuffers()
{
#ifdef __DREAMCAST__
glKosSwapBuffers();
#endif
}
int main(int argc, char* argv[])
{
initialize();
// Setup camera frustum
const float aspectRatio = 640.0f / 480.0f;
const float fov = 60;
const float zNear = 0.1f;
const float zFar = 1000.0f;
gluPerspective(fov, aspectRatio, zNear, zFar);
for (size_t i = 0; i < MAX_CUBES; i++)
{
const float r = rnd(0.1f, 0.5f);
const float x = rnd(-3.0f, 3.0f);
const float y = rnd(-3.0f, 3.0f);
const float z = rnd(-3.0f, 3.0f);
const float vx = rnd(-2.0f, 2.0f);
const float vy = rnd(-2.0f, 2.0f);
const float vz = rnd(-2.0f, 2.0f);
addCube(r, x, y, z, vx, vy, vz);
}
while (isRunning)
{
updateLogic();
updateInput();
swapBuffers();
runningStats();
}
avgStats();
return 0;
}

View File

@ -1,29 +0,0 @@
TARGET = depth_funcs.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,3 +1,7 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -34,6 +38,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
void DrawSquare(float width, float r, float g, float b, float z) {
width /= 2;
@ -113,6 +134,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,30 +0,0 @@
TARGET = depth_funcs_alpha_testing.elf
OBJS = main.o gl_png.o
KOS_CFLAGS += -std=c99
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -181,9 +181,9 @@ int dtex_to_gl_texture(texture *tex, char* filename) {
tex->blend_dest = GL_ONE_MINUS_SRC_ALPHA;
strcpy(tex->path, filename);
printf("Texture size: %d x %d\n", image->sizeX, image->sizeY);
printf("Texture size: %lu x %lu\n", image->sizeX, image->sizeY);
printf("Texture ratio: %d\n", ratio);
printf("Texture size: %d x %d\n", image->sizeX, image->sizeY);
printf("Texture size: %lu x %lu\n", image->sizeX, image->sizeY);
printf("Texture %s loaded\n", tex->path);
return(1);

View File

@ -1,3 +1,7 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -5,8 +9,14 @@
//$KOS_BASE/utils/texconv/texconv --in disk.png --format ARGB4444 --preview disk_preview.png --out disk.dtex
#ifdef __DREAMCAST__
extern uint8_t romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMAGE_FILENAME "/rd/disk_1555.dtex"
#else
#define IMAGE_FILENAME "../samples/depth_funcs/alpha_testing/romdisk/disk_1555.dtex"
#endif
texture t;
int blendActive = -1;
/* floats for x rotation, y rotation, z rotation */
@ -94,16 +104,37 @@ void DrawGLScene()
glKosSwapBuffers();
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
int main(int argc, char **argv)
{
glKosInit();
InitGL(640, 480);
//loads a dtex texture. see the /romdisk folder for more files
dtex_to_gl_texture(&t, "/rd/disk_1555.dtex");
dtex_to_gl_texture(&t, IMAGE_FILENAME);
ReSizeGLScene(640, 480);
DrawGLScene();
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = depth_funcs.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,3 +1,7 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -48,6 +52,24 @@ void DrawSquare(float width, float r, float g, float b, float z) {
glEnd(); // done with the polygon
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
{
@ -60,9 +82,9 @@ void DrawGLScene()
glDepthFunc(GL_LEQUAL);
//RED over GREEN over BLUE
DrawSquare(100.0, 1.0, 0.0, 0.0, 0.0);
glTranslatef(50, 0, 0.03f);
glTranslatef(50, 0, -0.03f);
DrawSquare(100, 0, 1, 0, 0);
glTranslatef(50, 0, 0.03f);
glTranslatef(50, 0, -0.03f);
DrawSquare(100, 0, 0, 1, 0);
// swap buffers to display, since we're double buffered.
@ -77,6 +99,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,30 +0,0 @@
TARGET = lerabot01.elf
OBJS = main.o
KOS_CFLAGS += -std=c99
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -2,6 +2,11 @@
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
@ -10,104 +15,19 @@
#ifdef __DREAMCAST__
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMAGE_FILENAME "/rd/flag1.bmp"
#else
#define IMAGE_FILENAME "../samples/lerabot01/romdisk/flag1.bmp"
#endif
#include "../loadbmp.h"
/* floats for x rotation, y rotation, z rotation */
float xrot, yrot, zrot;
/* storage for one texture */
int texture[1];
/* Image type - contains height, width, and data */
struct Image {
unsigned long sizeX;
unsigned long sizeY;
char *data;
};
typedef struct Image Image;
// quick and dirty bitmap loader...for 24 bit bitmaps with 1 plane only.
// See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/BMP.txt for more info.
int ImageLoad(char *filename, Image *image) {
FILE *file;
unsigned long size; // size of the image in bytes.
unsigned long i; // standard counter.
unsigned short int planes; // number of planes in image (must be 1)
unsigned short int bpp; // number of bits per pixel (must be 24)
char temp; // temporary color storage for bgr-rgb conversion.
// make sure the file is there.
if ((file = fopen(filename, "rb"))==NULL)
{
printf("File Not Found : %s\n",filename);
return 0;
}
// seek through the bmp header, up to the width/height:
fseek(file, 18, SEEK_CUR);
// read the width
if ((i = fread(&image->sizeX, 4, 1, file)) != 1) {
printf("Error reading width from %s.\n", filename);
return 0;
}
printf("Width of %s: %lu\n", filename, image->sizeX);
// read the height
if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
printf("Error reading height from %s.\n", filename);
return 0;
}
printf("Height of %s: %lu\n", filename, image->sizeY);
// calculate the size (assuming 24 bits or 3 bytes per pixel).
size = image->sizeX * image->sizeY * 3;
// read the planes
if ((fread(&planes, 2, 1, file)) != 1) {
printf("Error reading planes from %s.\n", filename);
return 0;
}
if (planes != 1) {
printf("Planes from %s is not 1: %u\n", filename, planes);
return 0;
}
// read the bpp
if ((i = fread(&bpp, 2, 1, file)) != 1) {
printf("Error reading bpp from %s.\n", filename);
return 0;
}
if (bpp != 24) {
printf("Bpp from %s is not 24: %u\n", filename, bpp);
return 0;
}
// seek past the rest of the bitmap header.
fseek(file, 24, SEEK_CUR);
// read the data.
image->data = (char *) malloc(size);
if (image->data == NULL) {
printf("Error allocating memory for color-corrected image data");
return 0;
}
if ((i = fread(image->data, size, 1, file)) != 1) {
printf(stderr, "Error reading image data from %s.\n", filename);
return 0;
}
for (i=0;i<size;i+=3) { // reverse all of the colors. (bgr -> rgb)
temp = image->data[i];
image->data[i] = image->data[i+2];
image->data[i+2] = temp;
}
// we're done.
return 1;
}
// Load Bitmaps And Convert To Textures
void LoadGLTextures() {
// Load Texture
@ -120,7 +40,7 @@ void LoadGLTextures() {
exit(0);
}
if (!ImageLoad("/rd/flag1.bmp", image1)) {
if (!ImageLoad(IMAGE_FILENAME, image1)) {
exit(1);
}
@ -134,6 +54,8 @@ void LoadGLTextures() {
// 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
// border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
free(image1);
};
/* A general OpenGL initialization function. Sets all of the initial parameters. */
@ -197,6 +119,24 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
void DrawTexturedQuad(int tex, float x, float y, float z)
{
GLfloat texW = 10;
@ -287,7 +227,7 @@ void DrawGLScene()
DrawTexturedQuad(texture[0], l1_pos[0], l1_pos[1], l1_pos[2]);
for (int i = 0; i < 5; i++)
DrawTexturedQuad(texture[0], i * 20, 0.0f, 0.0f); // Draw the textured quad.
DrawTexturedQuad(texture[0], i * 20, 0.0f, 0.1f); // Draw the textured quad.
// swap buffers to display, since we're double buffered.
glKosSwapBuffers();
@ -301,6 +241,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = blend_test.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,106 +0,0 @@
/*
* This sample is to demonstrate a bug where rendering an unblended
* polygon, before a series of blended ones would result in no blended
* output and incorrect depth testing
*/
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
/* A general OpenGL initialization function. Sets all of the initial parameters. */
void InitGL(int Width, int Height) // We call this right after our OpenGL window is created.
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // This Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glDisable(GL_BLEND);
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // Reset The Projection Matrix
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window
glMatrixMode(GL_MODELVIEW);
}
/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
void ReSizeGLScene(int Width, int Height)
{
if (Height == 0) // Prevent A Divide By Zero If The Window Is Too Small
Height = 1;
glViewport(0, 0, Width, Height); // Reset The Current Viewport And Perspective Transformation
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
}
void DrawQuad(const float* colour) {
glBegin(GL_QUADS);
glColor4fv(colour);
glVertex3f(-1.0,-1.0, 0.0);
glVertex3f( 1.0,-1.0, 0.0);
glVertex3f( 1.0, 1.0, 0.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd();
}
/* The main drawing function. */
void DrawGLScene()
{
const float RED [] = {1.0, 0, 0, 0.5};
const float BLUE [] = {0.0, 0, 1, 0.5};
const float NONE [] = {0, 0, 0, 0};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glTranslatef(-4.0, 0, -10);
// LEFT SECTION
// This should draw 2 quad, a red first, then and overlapping blue one.
// This section draw both quad at the same Z value
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
DrawQuad(RED);
glTranslatef(1.0, 0, 0);
DrawQuad(BLUE);
glDisable(GL_BLEND);
glTranslatef(4.0, 0, 0);
// RIGHT SECTION
// This should draw 2 quad, a red first, then and overlapping blue one.
// This section uses a LOWER Z VALUE(-0.01f), so the blue quad should be in FRONT of the red quad.
// lerabot's note : changing the z value to positive gives the desired output.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
DrawQuad(RED);
glTranslatef(1.0, 0, -0.01);
DrawQuad(BLUE);
glDisable(GL_BLEND);
glKosSwapBuffers();
}
int main(int argc, char **argv)
{
glKosInit();
InitGL(640, 480);
ReSizeGLScene(640, 480);
while(1) {
DrawGLScene();
}
return 0;
}

View File

@ -1,29 +0,0 @@
TARGET = lights.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,6 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
@ -8,113 +13,20 @@
#include "GL/glkos.h"
#ifdef __DREAMCAST__
#include <kos.h>
extern uint8_t romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMAGE_FILENAME "/rd/NeHe.bmp"
#else
#define IMAGE_FILENAME "samples/lights/romdisk/NeHe.bmp"
#define IMAGE_FILENAME "../samples/lights/romdisk/NeHe.bmp"
#endif
#include "../loadbmp.h"
float xrot, yrot, zrot;
int texture[1];
struct Image {
unsigned long sizeX;
unsigned long sizeY;
char *data;
};
typedef struct Image Image;
int ImageLoad(char *filename, Image *image) {
FILE *file;
unsigned long size;
unsigned long i;
unsigned short int planes;
unsigned short int bpp;
char temp;
if ((file = fopen(filename, "rb"))==NULL)
{
printf("File Not Found : %s\n",filename);
return 0;
}
fseek(file, 18, SEEK_CUR);
if ((i = fread(&image->sizeX, 4, 1, file)) != 1) {
printf("Error reading width from %s.\n", filename);
return 0;
}
printf("Width of %s: %lu\n", filename, image->sizeX);
if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
printf("Error reading height from %s.\n", filename);
return 0;
}
printf("Height of %s: %lu\n", filename, image->sizeY);
size = image->sizeX * image->sizeY * 3;
if ((fread(&planes, 2, 1, file)) != 1) {
printf("Error reading planes from %s.\n", filename);
return 0;
}
if (planes != 1) {
printf("Planes from %s is not 1: %u\n", filename, planes);
return 0;
}
if ((i = fread(&bpp, 2, 1, file)) != 1) {
printf("Error reading bpp from %s.\n", filename);
return 0;
}
if (bpp != 24) {
printf("Bpp from %s is not 24: %u\n", filename, bpp);
return 0;
}
fseek(file, 24, SEEK_CUR);
image->data = (char *) malloc(size);
if (image->data == NULL) {
printf("Error allocating memory for color-corrected image data");
return 0;
}
if ((i = fread(image->data, size, 1, file)) != 1) {
fprintf(stderr, "Error reading image data from %s.\n", filename);
return 0;
}
for (i=0;i<size;i+=3) {
temp = image->data[i];
image->data[i] = image->data[i+2];
image->data[i+2] = temp;
}
return 1;
}
void LoadGLTextures() {
Image *image1;
@ -141,6 +53,8 @@ void LoadGLTextures() {
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
glGenerateMipmapEXT(GL_TEXTURE_2D);
free(image1);
};
@ -211,9 +125,27 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
void DrawCube(float x, float z) {
static float pos = 0.0f;
const static float radius = 30.0f;
static const float radius = 30.0f;
pos += 0.001f;
@ -305,6 +237,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

94
samples/loadbmp.c Normal file
View File

@ -0,0 +1,94 @@
// quick and dirty bitmap loader...for 24 bit bitmaps with 1 plane only.
// See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/BMP.txt for more info.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "loadbmp.h"
int ImageLoad(char *filename, Image *image) {
FILE *file;
size_t size; // size of the image in bytes.
size_t i; // standard counter.
int32_t sizeX, sizeY; // width/height of the image - must be 4 bytes to match the file format
int16_t planes; // number of planes in image (must be 1)
int16_t bpp; // number of bits per pixel (must be 24)
char temp; // temporary color storage for bgr-rgb conversion.
// make sure the file is there.
if ((file = fopen(filename, "rb"))==NULL) {
printf("File Not Found : %s\n",filename);
return 0;
}
// seek through the bmp header, up to the width/height:
fseek(file, 10, SEEK_CUR);
uint32_t offset;
fread(&offset, 4, 1, file);
fseek(file, 4, SEEK_CUR);
// read the width
if ((i = fread(&sizeX, 4, 1, file)) != 1) {
printf("Error reading width from %s.\n", filename);
return 0;
}
image->sizeX = sizeX;
printf("Width of %s: %d\n", filename, sizeX);
// read the height
if ((i = fread(&sizeY, 4, 1, file)) != 1) {
printf("Error reading height from %s.\n", filename);
return 0;
}
image->sizeY = sizeY;
printf("Height of %s: %d\n", filename, sizeY);
// calculate the size (assuming 24 bits or 3 bytes per pixel).
size = image->sizeX * image->sizeY * 3;
// read the planes
if ((fread(&planes, 2, 1, file)) != 1) {
printf("Error reading planes from %s.\n", filename);
return 0;
}
if (planes != 1) {
printf("Planes from %s is not 1: %u\n", filename, planes);
return 0;
}
// read the bpp
if ((i = fread(&bpp, 2, 1, file)) != 1) {
printf("Error reading bpp from %s.\n", filename);
return 0;
}
if (bpp != 24) {
printf("Bpp from %s is not 24: %u\n", filename, bpp);
return 0;
}
// seek past the rest of the bitmap header.
fseek(file, offset, SEEK_SET);
// read the data.
image->data = (char *) malloc(size);
if (image->data == NULL) {
printf("Error allocating memory for color-corrected image data");
return 0;
}
if ((i = fread(image->data, size, 1, file)) != 1) {
printf("Error reading image data from %s.\n", filename);
return 0;
}
for (i=0;i<size;i+=3) { // reverse all of the colors. (bgr -> rgb)
temp = image->data[i];
image->data[i] = image->data[i+2];
image->data[i+2] = temp;
}
// we're done.
return 1;
}

16
samples/loadbmp.h Normal file
View File

@ -0,0 +1,16 @@
// quick and dirty bitmap loader...for 24 bit bitmaps with 1 plane only.
// See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/BMP.txt for more info.
#ifndef __LOADBMP_H
#define __LOADBMP_H
/* Image type - contains height, width, and data */
struct Image {
unsigned int sizeX;
unsigned int sizeY;
char *data;
};
typedef struct Image Image;
int ImageLoad(char *, Image *);
#endif

View File

@ -1,29 +0,0 @@
TARGET = mipmap.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -2,113 +2,28 @@
#include <stdlib.h>
#include <stdint.h>
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glext.h"
#include "GL/glkos.h"
#ifdef __DREAMCAST__
extern uint8_t romdisk[];
KOS_INIT_ROMDISK(romdisk);
#ifdef __DREAMCAST__
#define IMAGE_FILENAME "/rd/NeHe.bmp"
#else
#define IMAGE_FILENAME "samples/mipmap/romdisk/NeHe.bmp"
#define IMAGE_FILENAME "../samples/mipmap/romdisk/NeHe.bmp"
#endif
#include "../loadbmp.h"
/* storage for one texture */
int texture[1];
/* Image type - contains height, width, and data */
struct Image {
unsigned long sizeX;
unsigned long sizeY;
char *data;
};
typedef struct Image Image;
// quick and dirty bitmap loader...for 24 bit bitmaps with 1 plane only.
// See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/BMP.txt for more info.
int ImageLoad(char *filename, Image *image) {
FILE *file;
unsigned long size; // size of the image in bytes.
unsigned long i; // standard counter.
unsigned short int planes; // number of planes in image (must be 1)
unsigned short int bpp; // number of bits per pixel (must be 24)
char temp; // temporary color storage for bgr-rgb conversion.
// make sure the file is there.
if ((file = fopen(filename, "rb"))==NULL)
{
printf("File Not Found : %s\n",filename);
return 0;
}
// seek through the bmp header, up to the width/height:
fseek(file, 18, SEEK_CUR);
// read the width
if ((i = fread(&image->sizeX, 4, 1, file)) != 1) {
printf("Error reading width from %s.\n", filename);
return 0;
}
printf("Width of %s: %lu\n", filename, image->sizeX);
// read the height
if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
printf("Error reading height from %s.\n", filename);
return 0;
}
printf("Height of %s: %lu\n", filename, image->sizeY);
// calculate the size (assuming 24 bits or 3 bytes per pixel).
size = image->sizeX * image->sizeY * 3;
// read the planes
if ((fread(&planes, 2, 1, file)) != 1) {
printf("Error reading planes from %s.\n", filename);
return 0;
}
if (planes != 1) {
printf("Planes from %s is not 1: %u\n", filename, planes);
return 0;
}
// read the bpp
if ((i = fread(&bpp, 2, 1, file)) != 1) {
printf("Error reading bpp from %s.\n", filename);
return 0;
}
if (bpp != 24) {
printf("Bpp from %s is not 24: %u\n", filename, bpp);
return 0;
}
// seek past the rest of the bitmap header.
fseek(file, 24, SEEK_CUR);
// read the data.
image->data = (char *) malloc(size);
if (image->data == NULL) {
printf("Error allocating memory for color-corrected image data");
return 0;
}
if ((i = fread(image->data, size, 1, file)) != 1) {
fprintf(stderr, "Error reading image data from %s.\n", filename);
return 0;
}
for (i=0;i<size;i+=3) { // reverse all of the colors. (bgr -> rgb)
temp = image->data[i];
image->data[i] = image->data[i+2];
image->data[i+2] = temp;
}
// we're done.
return 1;
}
// Load Bitmaps And Convert To Textures
void LoadGLTextures() {
// Load Texture
@ -132,11 +47,11 @@ void LoadGLTextures() {
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); // scale linearly when image smalled than texture
// 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
// border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
// 2d texture, 3 components (red, green, blue), x size from image, y size from image,
// rgb color data, unsigned byte data, and finally the data itself.
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image1->sizeX, image1->sizeY, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
glGenerateMipmapEXT(GL_TEXTURE_2D);
free(image1);
};
/* A general OpenGL initialization function. Sets all of the initial parameters. */
@ -173,6 +88,24 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
void DrawQuad() {
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left Of The Texture and Quad
@ -236,6 +169,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = multitexture_arrays.elf
OBJS = main.o pvr-texture.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -11,17 +11,23 @@
#include <stdlib.h>
#include <stdint.h>
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
#include "GL/glext.h"
#ifdef __DREAMCAST__
extern uint8_t romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMAGE1_FILENAME "/rd/wp001vq.pvr"
#define IMAGE2_FILENAME "/rd/FlareWS_256.pvr"
#else
#define IMAGE1_FILENAME "samples/multitexture_arrays/romdisk/wp001vq.pvr"
#define IMAGE2_FILENAME "samples/multitexture_arrays/romdisk/FlareWS_256.pvr"
#define IMAGE1_FILENAME "../samples/multitexture_arrays/romdisk/wp001vq.pvr"
#define IMAGE2_FILENAME "../samples/multitexture_arrays/romdisk/FlareWS_256.pvr"
#endif
/* Load a PVR texture - located in pvr-texture.c */
@ -41,6 +47,23 @@ GLfloat TEXCOORD_ARRAY[4 * 2] = { 0, 0,
GLuint ARGB_ARRAY[4] = { 0xFFFF0000, 0xFF0000FF, 0xFF00FF00, 0xFFFFFF00 };
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* Multi-Texture Example using Open GL Vertex Buffer Submission. */
void RenderCallback(GLuint texID0, GLuint texID1) {
@ -101,9 +124,6 @@ void RenderCallback(GLuint texID0, GLuint texID1) {
glDisableClientState(GL_VERTEX_ARRAY);
}
extern uint8_t romdisk[];
KOS_INIT_ROMDISK(romdisk);
int main(int argc, char **argv) {
/* Notice we do not init the PVR here, that is handled by Open GL */
glKosInit();
@ -119,6 +139,9 @@ int main(int argc, char **argv) {
GLuint texID1 = glTextureLoadPVR(IMAGE2_FILENAME, 0, 0);
while(1) {
if(check_start())
break;
/* Draw the "scene" */
RenderCallback(texID0, texID1);

View File

@ -62,7 +62,7 @@ GLuint glTextureLoadPVR(char *fname, unsigned char isMipMapped, unsigned char gl
if(tex == NULL) {
printf("FILE READ ERROR: %s\n", fname);
while(1);
return 1;
}
fseek(tex, 0, SEEK_END);

View File

@ -1,29 +0,0 @@
TARGET = nehe02.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,3 +1,7 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -5,7 +9,7 @@
/* A general OpenGL initialization function. Sets all of the initial parameters. */
void InitGL(int Width, int Height) // We call this right after our OpenGL window is created.
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
glClearColor(0.0f, 0.0f, 1.0f, 0.0f); // This Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
@ -16,7 +20,7 @@ void InitGL(int Width, int Height) // We call this right after our OpenG
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window
glMatrixMode(GL_MODELVIEW);
glMatrixMode(GL_MODELVIEW);
}
/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
@ -34,6 +38,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -116,6 +137,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = nehe02de.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,3 +1,7 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -36,6 +40,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -87,6 +108,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = nehe02va.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,3 +1,7 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -36,6 +40,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -79,6 +100,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = nehe03.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,3 +1,6 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
@ -35,6 +38,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -77,6 +97,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = nehe04.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,3 +1,7 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -37,6 +41,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -87,6 +108,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = nehe05.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,3 +1,7 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -37,6 +41,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -140,6 +161,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = nehe06.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -3,115 +3,31 @@
#include <stdlib.h>
#include <stdio.h>
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glext.h"
#include "GL/glkos.h"
#ifdef __DREAMCAST__
#define IMAGE_FILENAME "/rd/NeHe.bmp"
extern uint8_t romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMAGE_FILENAME "/rd/NeHe.bmp"
#else
#define IMAGE_FILENAME "samples/nehe06/romdisk/NeHe.bmp"
#define IMAGE_FILENAME "../samples/nehe06/romdisk/NeHe.bmp"
#endif
#include "../loadbmp.h"
/* floats for x rotation, y rotation, z rotation */
float xrot, yrot, zrot;
/* storage for one texture */
GLuint texture[1];
/* Image type - contains height, width, and data */
struct Image {
unsigned long sizeX;
unsigned long sizeY;
char *data;
};
typedef struct Image Image;
// quick and dirty bitmap loader...for 24 bit bitmaps with 1 plane only.
// See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/BMP.txt for more info.
int ImageLoad(char *filename, Image *image) {
FILE *file;
unsigned long size; // size of the image in bytes.
unsigned long i; // standard counter.
unsigned short int planes; // number of planes in image (must be 1)
unsigned short int bpp; // number of bits per pixel (must be 24)
char temp; // temporary color storage for bgr-rgb conversion.
// make sure the file is there.
if ((file = fopen(filename, "rb"))==NULL)
{
printf("File Not Found : %s\n",filename);
return 0;
}
// seek through the bmp header, up to the width/height:
fseek(file, 18, SEEK_CUR);
// read the width
if ((i = fread(&image->sizeX, 4, 1, file)) != 1) {
printf("Error reading width from %s.\n", filename);
return 0;
}
printf("Width of %s: %lu\n", filename, image->sizeX);
// read the height
if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
printf("Error reading height from %s.\n", filename);
return 0;
}
printf("Height of %s: %lu\n", filename, image->sizeY);
// calculate the size (assuming 24 bits or 3 bytes per pixel).
size = image->sizeX * image->sizeY * 3;
// read the planes
if ((fread(&planes, 2, 1, file)) != 1) {
printf("Error reading planes from %s.\n", filename);
return 0;
}
if (planes != 1) {
printf("Planes from %s is not 1: %u\n", filename, planes);
return 0;
}
// read the bpp
if ((i = fread(&bpp, 2, 1, file)) != 1) {
printf("Error reading bpp from %s.\n", filename);
return 0;
}
if (bpp != 24) {
printf("Bpp from %s is not 24: %u\n", filename, bpp);
return 0;
}
// seek past the rest of the bitmap header.
fseek(file, 24, SEEK_CUR);
// read the data.
image->data = (char *) malloc(size);
if (image->data == NULL) {
printf("Error allocating memory for color-corrected image data");
return 0;
}
if ((i = fread(image->data, size, 1, file)) != 1) {
fprintf(stderr, "Error reading image data from %s.\n", filename);
return 0;
}
for (i=0;i<size;i+=3) { // reverse all of the colors. (bgr -> rgb)
temp = image->data[i];
image->data[i] = image->data[i+2];
image->data[i+2] = temp;
}
// we're done.
return 1;
}
// Load Bitmaps And Convert To Textures
void LoadGLTextures() {
// Load Texture
@ -133,14 +49,14 @@ void LoadGLTextures() {
glBindTexture(GL_TEXTURE_2D, texture[0]); // 2d texture (x and y size)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); // scale linearly when image smalled than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smaller than texture
// 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
// border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
glGenerateMipmapEXT(GL_TEXTURE_2D);
};
free(image1);
}
/* A general OpenGL initialization function. Sets all of the initial parameters. */
void InitGL(int Width, int Height) // We call this right after our OpenGL window is created.
@ -158,7 +74,7 @@ void InitGL(int Width, int Height) // We call this right after our OpenG
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window
glMatrixMode(GL_MODELVIEW);
glMatrixMode(GL_MODELVIEW);
}
/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
@ -176,6 +92,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -247,6 +180,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

@ -2,17 +2,21 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
#include "GL/glext.h"
#ifdef __DREAMCAST__
#define IMG_PATH "/rd/NeHe.tex"
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMG_PATH "/rd/NeHe.tex"
#else
#define IMG_PATH "samples/nehe06_4444twid/romdisk/NeHe.tex"
#define IMG_PATH "../samples/nehe06_4444twid/romdisk/NeHe.tex"
#endif
/* floats for x rotation, y rotation, z rotation */
@ -55,10 +59,10 @@ int ImageLoad(char *filename, Image *image) {
fread(&header, sizeof(header), 1, file);
GLboolean twiddled = (header.type & (1 << 25)) < 1;
GLboolean compressed = (header.type & (1 << 29)) > 0;
GLboolean mipmapped = (header.type & (1 << 30)) > 0;
GLboolean strided = (header.type & (1 << 24)) > 0;
GLboolean twiddled = (header.type & (1 << 26)) < 1;
GLboolean compressed = (header.type & (1 << 30)) > 0;
GLboolean mipmapped = (header.type & (1 << 31)) > 0;
GLboolean strided = (header.type & (1 << 25)) > 0;
GLuint format = (header.type >> 27) & 0b111;
image->data = (char *) malloc (header.size);
@ -156,6 +160,8 @@ void LoadGLTextures() {
GL_TEXTURE_2D, 0, image1->internal_format, image1->sizeX, image1->sizeY, 0,
image1->format, image1->type, image1->data
);
free(image1);
};
/* A general OpenGL initialization function. Sets all of the initial parameters. */
@ -192,6 +198,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -263,6 +286,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = nehe06_vq.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,6 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -9,6 +13,9 @@
#ifdef __DREAMCAST__
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMG_PATH "/rd/NeHe.tex"
#else
#define IMG_PATH "../samples/nehe06_vq/romdisk/NeHe.tex"
#endif
/* floats for x rotation, y rotation, z rotation */
@ -145,7 +152,7 @@ void LoadGLTextures() {
exit(0);
}
if (!ImageLoad("/rd/NeHe.tex", image1)) {
if (!ImageLoad(IMG_PATH, image1)) {
exit(1);
}
@ -162,6 +169,8 @@ void LoadGLTextures() {
GL_TEXTURE_2D, 0, image1->internalFormat, image1->sizeX, image1->sizeY, 0,
image1->dataSize, image1->data
);
free(image1);
};
/* A general OpenGL initialization function. Sets all of the initial parameters. */
@ -198,6 +207,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -269,6 +295,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

249
samples/nehe08/main.c Normal file
View File

@ -0,0 +1,249 @@
/*
KallistiOS 2.0.0
nehe08.c
(c)2021 Luke Benstead
(c)2014 Josh Pearson
(c)2001 Benoit Miller
(c)2000 Jeff Molofee
*/
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glkos.h>
/* Simple OpenGL example to demonstrate blending and lighting.
Essentially the same thing as NeHe's lesson08 code.
To learn more, go to http://nehe.gamedev.net/.
DPAD controls the cube rotation, button A & B control the depth
of the cube, button X toggles filtering, and button Y toggles alpha
blending.
*/
#ifdef __DREAMCAST__
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMG_PATH "/rd/glass.pvr"
#else
#define IMG_PATH "../samples/nehe08/romdisk/glass.pvr"
#endif
static GLfloat xrot; /* X Rotation */
static GLfloat yrot; /* Y Rotation */
static GLfloat xspeed; /* X Rotation Speed */
static GLfloat yspeed; /* Y Rotation Speed */
static GLfloat z = -5.0f; /* Depth Into The Screen */
GLboolean xp = GL_FALSE;
GLboolean yp = GL_FALSE;
GLboolean blend = GL_FALSE;
static GLuint filter; /* Which Filter To Use */
static GLuint texture[2]; /* Storage For Two Textures */
/* Load a PVR texture - located in pvr-texture.c */
extern GLuint glTextureLoadPVR(char *fname, unsigned char isMipMapped, unsigned char glMipMap);
/* A general OpenGL initialization function. Sets all of the initial parameters. */
void InitGL(int Width, int Height) // We call this right after our OpenGL window is created.
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)Width/(GLfloat)Height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glColor4f(1.0f, 1.0f, 1.0f, 0.5);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
/* Enable Lighting and GL_LIGHT0 */
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
/* Set up the textures */
texture[0] = glTextureLoadPVR(IMG_PATH, 0, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
texture[1] = glTextureLoadPVR(IMG_PATH, 0, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
void DrawGLScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, z);
glRotatef(xrot, 1.0f, 0.0f, 0.0f);
glRotatef(yrot, 0.0f, 1.0f, 0.0f);
glBindTexture(GL_TEXTURE_2D, texture[filter]);
glBegin(GL_QUADS);
/* Front Face */
glNormal3f(0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
/* Back Face */
glNormal3f(0.0f, 0.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
/* Top Face */
glNormal3f(0.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
/* Bottom Face */
glNormal3f(0.0f, -1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
/* Right face */
glNormal3f(1.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 1.0f);
/* Left Face */
glNormal3f(-1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
xrot += xspeed;
yrot += yspeed;
/* Finish the frame */
glKosSwapBuffers();
}
int ReadController(void) {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
/* Check key status */
state = (cont_state_t *)maple_dev_status(cont);
if(!state) {
printf("Error reading controller\n");
return 0;
}
if(state->buttons & CONT_START)
return 0;
if(state->buttons & CONT_A)
z -= 0.02f;
if(state->buttons & CONT_B)
z += 0.02f;
if((state->buttons & CONT_X) && !xp) {
xp = GL_TRUE;
filter += 1;
if(filter > 1)
filter = 0;
}
if(!(state->buttons & CONT_X))
xp = GL_FALSE;
if((state->buttons & CONT_Y) && !yp) {
yp = GL_TRUE;
blend = !blend;
}
if(!(state->buttons & CONT_Y))
yp = GL_FALSE;
if(state->buttons & CONT_DPAD_UP)
xspeed -= 0.01f;
if(state->buttons & CONT_DPAD_DOWN)
xspeed += 0.01f;
if(state->buttons & CONT_DPAD_LEFT)
yspeed -= 0.01f;
if(state->buttons & CONT_DPAD_RIGHT)
yspeed += 0.01f;
#endif
/* Switch to the blended polygon list if needed */
if(blend) {
glEnable(GL_BLEND);
glDepthMask(0);
}
else {
glDisable(GL_BLEND);
glDepthMask(1);
}
return 1;
}
int main(int argc, char **argv) {
printf("nehe08 beginning\n");
/* Get basic stuff initialized */
glKosInit();
InitGL(640, 480);
while(1) {
if (!ReadController())
break;
DrawGLScene();
}
return 0;
}

View File

@ -0,0 +1,176 @@
/*
KallistiOS 2.0.0
pvr-texture.c
(c)2014 Josh PH3NOM Pearson
Load A PVR Texture to the PVR using Open GL
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
#include "GL/glext.h"
#define PVR_HDR_SIZE 0x20
#define MAX(x, y) ((x > y) ? x : y)
static GLuint PVR_TextureHeight(unsigned char *HDR);
static GLuint PVR_TextureWidth(unsigned char *HDR);
static GLuint PVR_TextureFormat(unsigned char *HDR);
static GLuint _glGetMipmapLevelCount(GLuint width, GLuint height) {
return 1 + floor(log2(MAX(width, height)));
}
static GLuint _glGetMipmapDataSize(GLuint width, GLuint height) {
GLuint size = 0;
GLuint i = 0;
for(; i < _glGetMipmapLevelCount(width, height); ++i) {
size += (width * height * 2);
if(width > 1) {
width /= 2;
}
if(height > 1) {
height /= 2;
}
}
return size;
}
/* Load a PVR texture file into memory, and then bind the texture to Open GL.
fname is the name of the PVR texture file to be opened and read.
isMipMapped should be passed as 1 if the texture contains MipMap levels, 0 otherwise.
glMipMap should be passed as 1 if Open GL should calculate the Mipmap levels, 0 otherwise */
GLuint glTextureLoadPVR(char *fname, unsigned char isMipMapped, unsigned char glMipMap) {
FILE *tex = NULL;
uint16_t *TEX0 = NULL;
uint8_t HDR[PVR_HDR_SIZE];
GLuint texID, texSize, texW, texH, texFormat;
/* Open the PVR texture file, and get its file size */
tex = fopen(fname, "rb");
if(tex == NULL) {
printf("FILE READ ERROR: %s\n", fname);
while(1);
}
fseek(tex, 0, SEEK_END);
texSize = ftell(tex) - PVR_HDR_SIZE;
fseek(tex, 0, SEEK_SET);
/* Read in the PVR texture file header */
fread(HDR, 1, PVR_HDR_SIZE, tex);
/* Extract some information from the PVR texture file header */
texW = PVR_TextureWidth(HDR);
texH = PVR_TextureHeight(HDR);
texFormat = PVR_TextureFormat(HDR);
/* Allocate Some Memory for the texture. If we are using Open GL to build the MipMap,
we need to allocate enough space to hold the MipMap texture levels. */
if(!isMipMapped && glMipMap)
TEX0 = malloc(_glGetMipmapDataSize(texW, texH));
else
TEX0 = malloc(texSize);
fread(TEX0, 1, texSize, tex); /* Read in the PVR texture data */
/* Generate and bind a texture as normal for Open GL */
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
if(texFormat != GL_UNSIGNED_SHORT_5_6_5)
glCompressedTexImage2DARB(GL_TEXTURE_2D,
0,
texFormat,
texW,
texH,
0,
texSize,
TEX0);
else {
fprintf(stderr, "%x\n", texFormat);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
texW, texH,
0,
GL_RGB,
texFormat,
TEX0);
if(!isMipMapped && glMipMap)
glGenerateMipmapEXT(GL_TEXTURE_2D);
}
free(TEX0);
return texID;
}
static GLuint PVR_TextureFormat(unsigned char *HDR) {
GLuint color = (GLuint)HDR[PVR_HDR_SIZE - 8];
GLuint format = (GLuint)HDR[PVR_HDR_SIZE - 7];
GLboolean twiddled = format == 0x01;
GLboolean compressed = (format == 0x10 || format == 0x03);
if(compressed) {
if(twiddled) {
switch(color) {
case 0x0: {
return GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS;
} break;
case 0x01: {
return GL_COMPRESSED_RGB_565_VQ_TWID_KOS;
} break;
case 0x02: {
return GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS;
}
break;
default:
fprintf(stderr, "Invalid texture format");
return 0;
}
} else {
switch(color) {
case 0: {
return GL_COMPRESSED_ARGB_1555_VQ_KOS;
} break;
case 1: {
return GL_COMPRESSED_RGB_565_VQ_KOS;
} break;
case 2: {
return GL_COMPRESSED_ARGB_4444_VQ_KOS;
}
break;
default:
fprintf(stderr, "Invalid texture format");
return 0;
}
}
} else {
if(color == 1) {
return GL_UNSIGNED_SHORT_5_6_5;
}
return 0;
}
}
static GLuint PVR_TextureWidth(unsigned char *HDR) {
return (GLuint)HDR[PVR_HDR_SIZE - 4] | HDR[PVR_HDR_SIZE - 3] << 8;
}
static GLuint PVR_TextureHeight(unsigned char *HDR) {
return (GLuint)HDR[PVR_HDR_SIZE - 2] | HDR[PVR_HDR_SIZE - 1] << 8;
}

Binary file not shown.

353
samples/nehe10/main.c Normal file
View File

@ -0,0 +1,353 @@
/*
KallistiOS 2.0.0
nehe08.c
(c)2021 Luke Benstead
(c)2014 Josh Pearson
(c)2001 Benoit Miller
(c)2000 Jeff Molofee
*/
#ifdef __DREAMCAST__
#include <kos.h>
#else
#include <SDL.h>
#endif
#include <stdio.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glkos.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include "../loadbmp.h"
#ifdef __DREAMCAST__
extern uint8 romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMG_PATH "/rd/brick.bmp"
#else
#define IMG_PATH "../samples/nehe10/romdisk/brick.bmp"
#endif
bool keys[256]; // Array Used For The Keyboard Routine
bool active = GL_TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen = GL_TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default
bool blend; // Blending ON/OFF
bool bp; // B Pressed?
bool fp; // F Pressed?
const float piover180 = 0.0174532925f;
float heading;
float xpos;
float zpos;
GLfloat yrot; // Y Rotation
GLfloat walkbias = 0;
GLfloat walkbiasangle = 0;
GLfloat lookupdown = 0.0f;
GLfloat z=0.0f; // Depth Into The Screen
GLuint filter; // Which Filter To Use
GLuint texture[3]; // Storage For 3 Textures
typedef struct tagVERTEX
{
float x, y, z;
float u, v;
} VERTEX;
typedef struct tagTRIANGLE
{
VERTEX vertex[3];
} TRIANGLE;
typedef struct tagSECTOR
{
int numtriangles;
TRIANGLE* triangle;
} SECTOR;
SECTOR sector1;
void readstr(FILE *f,char *string)
{
do
{
fgets(string, 255, f);
} while ((string[0] == '/') || (string[0] == '\n'));
return;
}
void SetupWorld()
{
float x, y, z, u, v;
int numtriangles;
FILE *filein;
char oneline[255];
#ifdef __DREAMCAST__
filein = fopen("/rd/world.txt", "rt"); // File To Load World Data From
#else
filein = fopen("../samples/nehe10/romdisk/world.txt", "rt");
#endif
if(!filein) {
fprintf(stderr, "Failed to load world file\n");
exit(1);
}
readstr(filein,oneline);
sscanf(oneline, "NUMPOLLIES %d\n", &numtriangles);
sector1.triangle = (TRIANGLE*) malloc(sizeof(TRIANGLE) * numtriangles);
sector1.numtriangles = numtriangles;
for (int loop = 0; loop < numtriangles; loop++)
{
for (int vert = 0; vert < 3; vert++)
{
readstr(filein,oneline);
sscanf(oneline, "%f %f %f %f %f", &x, &y, &z, &u, &v);
sector1.triangle[loop].vertex[vert].x = x;
sector1.triangle[loop].vertex[vert].y = y;
sector1.triangle[loop].vertex[vert].z = z;
sector1.triangle[loop].vertex[vert].u = u;
sector1.triangle[loop].vertex[vert].v = v;
}
}
fclose(filein);
return;
}
int LoadGLTextures() // Load Bitmaps And Convert To Textures
{
int Status = GL_FALSE; // Status Indicator
Image image1;
// Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit
if (ImageLoad(IMG_PATH, &image1))
{
Status = GL_TRUE; // Set The Status To TRUE
glGenTextures(3, &texture[0]); // Create Three Textures
// Create Nearest Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1.sizeX, image1.sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1.data);
// Create Linear Filtered Texture
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1.sizeX, image1.sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1.data);
// Create MipMapped Texture
glBindTexture(GL_TEXTURE_2D, texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image1.sizeX, image1.sizeY, GL_RGB, GL_UNSIGNED_BYTE, image1.data);
}
return Status; // Return The Status
}
/* A general OpenGL initialization function. Sets all of the initial parameters. */
GLboolean InitGL(int width, int height) // We call this right after our OpenGL window is created.
{
glViewport(0, 0, width, height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity();
if (!LoadGLTextures()) // Jump To Texture Loading Routine
{
return GL_FALSE; // If Texture Didn't Load Return false
}
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Set The Blending Function For Translucency
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
SetupWorld();
return GL_TRUE;
}
void DrawGLScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
GLfloat x_m, y_m, z_m, u_m, v_m;
GLfloat xtrans = -xpos;
GLfloat ztrans = -zpos;
GLfloat ytrans = -walkbias-0.25f;
GLfloat sceneroty = 360.0f - yrot;
int numtriangles;
glRotatef(lookupdown,1.0f,0,0);
glRotatef(sceneroty,0,1.0f,0);
glTranslatef(xtrans, ytrans, ztrans);
glBindTexture(GL_TEXTURE_2D, texture[filter]);
numtriangles = sector1.numtriangles;
// Process Each Triangle
for (int loop_m = 0; loop_m < numtriangles; loop_m++)
{
glBegin(GL_TRIANGLES);
glNormal3f( 0.0f, 0.0f, 1.0f);
x_m = sector1.triangle[loop_m].vertex[0].x;
y_m = sector1.triangle[loop_m].vertex[0].y;
z_m = sector1.triangle[loop_m].vertex[0].z;
u_m = sector1.triangle[loop_m].vertex[0].u;
v_m = sector1.triangle[loop_m].vertex[0].v;
glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m);
x_m = sector1.triangle[loop_m].vertex[1].x;
y_m = sector1.triangle[loop_m].vertex[1].y;
z_m = sector1.triangle[loop_m].vertex[1].z;
u_m = sector1.triangle[loop_m].vertex[1].u;
v_m = sector1.triangle[loop_m].vertex[1].v;
glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m);
x_m = sector1.triangle[loop_m].vertex[2].x;
y_m = sector1.triangle[loop_m].vertex[2].y;
z_m = sector1.triangle[loop_m].vertex[2].z;
u_m = sector1.triangle[loop_m].vertex[2].u;
v_m = sector1.triangle[loop_m].vertex[2].v;
glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m);
glEnd();
}
/* Finish the frame */
glKosSwapBuffers();
}
int ReadController(void) {
bool start = false;
bool up = false;
bool down = false;
bool left = false;
bool right = false;
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
/* Check key status */
state = (cont_state_t *)maple_dev_status(cont);
if(!state) {
printf("Error reading controller\n");
return 0;
}
start = (state->buttons & CONT_START);
up = (state->buttons & CONT_DPAD_UP);
down = (state->buttons & CONT_DPAD_DOWN);
left = (state->buttons & CONT_DPAD_LEFT);
right = (state->buttons & CONT_DPAD_RIGHT);
#else
int num_keys = 0;
uint8_t* state = SDL_GetKeyboardState(&num_keys);
start = state[SDL_SCANCODE_RETURN];
up = state[SDL_SCANCODE_UP];
down = state[SDL_SCANCODE_DOWN];
left = state[SDL_SCANCODE_LEFT];
right = state[SDL_SCANCODE_RIGHT];
#endif
if(start) {
return 0;
}
if(up) {
xpos -= (float)sin(heading*piover180) * 0.05f;
zpos -= (float)cos(heading*piover180) * 0.05f;
if (walkbiasangle >= 359.0f)
{
walkbiasangle = 0.0f;
}
else
{
walkbiasangle+= 10;
}
walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
}
if(down) {
xpos += (float)sin(heading*piover180) * 0.05f;
zpos += (float)cos(heading*piover180) * 0.05f;
if (walkbiasangle <= 1.0f)
{
walkbiasangle = 359.0f;
}
else
{
walkbiasangle-= 10;
}
walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
}
if(left) {
heading += 1.0f;
yrot = heading;
}
if(right) {
heading -= 1.0f;
yrot = heading;
}
/* Switch to the blended polygon list if needed */
if(blend) {
glEnable(GL_BLEND);
glDepthMask(0);
}
else {
glDisable(GL_BLEND);
glDepthMask(1);
}
return 1;
}
int main(int argc, char **argv) {
printf("nehe10 beginning\n");
/* Get basic stuff initialized */
glKosInit();
InitGL(640, 480);
while(1) {
if (!ReadController())
break;
DrawGLScene();
}
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -0,0 +1,160 @@
NUMPOLLIES 36
// Floor 1
-3.0 0.0 -3.0 0.0 6.0
-3.0 0.0 3.0 0.0 0.0
3.0 0.0 3.0 6.0 0.0
-3.0 0.0 -3.0 0.0 6.0
3.0 0.0 -3.0 6.0 6.0
3.0 0.0 3.0 6.0 0.0
// Ceiling 1
-3.0 1.0 -3.0 0.0 6.0
-3.0 1.0 3.0 0.0 0.0
3.0 1.0 3.0 6.0 0.0
-3.0 1.0 -3.0 0.0 6.0
3.0 1.0 -3.0 6.0 6.0
3.0 1.0 3.0 6.0 0.0
// A1
-2.0 1.0 -2.0 0.0 1.0
-2.0 0.0 -2.0 0.0 0.0
-0.5 0.0 -2.0 1.5 0.0
-2.0 1.0 -2.0 0.0 1.0
-0.5 1.0 -2.0 1.5 1.0
-0.5 0.0 -2.0 1.5 0.0
// A2
2.0 1.0 -2.0 2.0 1.0
2.0 0.0 -2.0 2.0 0.0
0.5 0.0 -2.0 0.5 0.0
2.0 1.0 -2.0 2.0 1.0
0.5 1.0 -2.0 0.5 1.0
0.5 0.0 -2.0 0.5 0.0
// B1
-2.0 1.0 2.0 2.0 1.0
-2.0 0.0 2.0 2.0 0.0
-0.5 0.0 2.0 0.5 0.0
-2.0 1.0 2.0 2.0 1.0
-0.5 1.0 2.0 0.5 1.0
-0.5 0.0 2.0 0.5 0.0
// B2
2.0 1.0 2.0 2.0 1.0
2.0 0.0 2.0 2.0 0.0
0.5 0.0 2.0 0.5 0.0
2.0 1.0 2.0 2.0 1.0
0.5 1.0 2.0 0.5 1.0
0.5 0.0 2.0 0.5 0.0
// C1
-2.0 1.0 -2.0 0.0 1.0
-2.0 0.0 -2.0 0.0 0.0
-2.0 0.0 -0.5 1.5 0.0
-2.0 1.0 -2.0 0.0 1.0
-2.0 1.0 -0.5 1.5 1.0
-2.0 0.0 -0.5 1.5 0.0
// C2
-2.0 1.0 2.0 2.0 1.0
-2.0 0.0 2.0 2.0 0.0
-2.0 0.0 0.5 0.5 0.0
-2.0 1.0 2.0 2.0 1.0
-2.0 1.0 0.5 0.5 1.0
-2.0 0.0 0.5 0.5 0.0
// D1
2.0 1.0 -2.0 0.0 1.0
2.0 0.0 -2.0 0.0 0.0
2.0 0.0 -0.5 1.5 0.0
2.0 1.0 -2.0 0.0 1.0
2.0 1.0 -0.5 1.5 1.0
2.0 0.0 -0.5 1.5 0.0
// D2
2.0 1.0 2.0 2.0 1.0
2.0 0.0 2.0 2.0 0.0
2.0 0.0 0.5 0.5 0.0
2.0 1.0 2.0 2.0 1.0
2.0 1.0 0.5 0.5 1.0
2.0 0.0 0.5 0.5 0.0
// Upper hallway - L
-0.5 1.0 -3.0 0.0 1.0
-0.5 0.0 -3.0 0.0 0.0
-0.5 0.0 -2.0 1.0 0.0
-0.5 1.0 -3.0 0.0 1.0
-0.5 1.0 -2.0 1.0 1.0
-0.5 0.0 -2.0 1.0 0.0
// Upper hallway - R
0.5 1.0 -3.0 0.0 1.0
0.5 0.0 -3.0 0.0 0.0
0.5 0.0 -2.0 1.0 0.0
0.5 1.0 -3.0 0.0 1.0
0.5 1.0 -2.0 1.0 1.0
0.5 0.0 -2.0 1.0 0.0
// Lower hallway - L
-0.5 1.0 3.0 0.0 1.0
-0.5 0.0 3.0 0.0 0.0
-0.5 0.0 2.0 1.0 0.0
-0.5 1.0 3.0 0.0 1.0
-0.5 1.0 2.0 1.0 1.0
-0.5 0.0 2.0 1.0 0.0
// Lower hallway - R
0.5 1.0 3.0 0.0 1.0
0.5 0.0 3.0 0.0 0.0
0.5 0.0 2.0 1.0 0.0
0.5 1.0 3.0 0.0 1.0
0.5 1.0 2.0 1.0 1.0
0.5 0.0 2.0 1.0 0.0
// Left hallway - Lw
-3.0 1.0 0.5 1.0 1.0
-3.0 0.0 0.5 1.0 0.0
-2.0 0.0 0.5 0.0 0.0
-3.0 1.0 0.5 1.0 1.0
-2.0 1.0 0.5 0.0 1.0
-2.0 0.0 0.5 0.0 0.0
// Left hallway - Hi
-3.0 1.0 -0.5 1.0 1.0
-3.0 0.0 -0.5 1.0 0.0
-2.0 0.0 -0.5 0.0 0.0
-3.0 1.0 -0.5 1.0 1.0
-2.0 1.0 -0.5 0.0 1.0
-2.0 0.0 -0.5 0.0 0.0
// Right hallway - Lw
3.0 1.0 0.5 1.0 1.0
3.0 0.0 0.5 1.0 0.0
2.0 0.0 0.5 0.0 0.0
3.0 1.0 0.5 1.0 1.0
2.0 1.0 0.5 0.0 1.0
2.0 0.0 0.5 0.0 0.0
// Right hallway - Hi
3.0 1.0 -0.5 1.0 1.0
3.0 0.0 -0.5 1.0 0.0
2.0 0.0 -0.5 0.0 0.0
3.0 1.0 -0.5 1.0 1.0
2.0 1.0 -0.5 0.0 1.0
2.0 0.0 -0.5 0.0 0.0

269
samples/nehe20/main.c Normal file
View File

@ -0,0 +1,269 @@
/* DREAMCAST
*IAN MICHEAL Ported SDL+OPENGL USING SDL[DREAMHAL][GLDC][KOS2.0]2021
* Cleaned and tested on dreamcast hardware by Ianmicheal
* This Code Was Created By Pet & Commented/Cleaned Up By Jeff Molofee
* If You've Found This Code Useful, Please Let Me Know.
* Visit NeHe Productions At http://nehe.gamedev.net
*/
#include <math.h> // Header File For Windows Math Library
#include <stdio.h> // Header File For Standard Input/Output
#include <stdint.h>
#include <stdlib.h>
#define FPS 60
uint32_t waittime = 1000.0f/FPS;
uint32_t framestarttime = 0;
int32_t delaytime;
#ifdef __DREAMCAST__
extern uint8_t romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMG_LOGO_PATH "/rd/logo.bmp"
#define IMG_MASK1_PATH "/rd/mask1.bmp"
#define IMG_IMAGE1_PATH "/rd/image1.bmp"
#define IMG_MASK2_PATH "/rd/mask2.bmp"
#define IMG_IMAGE2_PATH "/rd/image2.bmp"
#else
#define IMG_LOGO_PATH "../samples/nehe20/romdisk/logo.bmp"
#define IMG_MASK1_PATH "../samples/nehe20/romdisk/mask1.bmp"
#define IMG_IMAGE1_PATH "../samples/nehe20/romdisk/image1.bmp"
#define IMG_MASK2_PATH "../samples/nehe20/romdisk/mask2.bmp"
#define IMG_IMAGE2_PATH "../samples/nehe20/romdisk/image2.bmp"
#endif
#include "../loadbmp.h"
/*
* This Code Was Created By Jeff Molofee 2000
* And Modified By Giuseppe D'Agata (waveform@tiscalinet.it)
* If You've Found This Code Useful, Please Let Me Know.
* Visit My Site At nehe.gamedev.net
*/
#include <math.h> // Header File For Windows Math Library
#include <stdio.h> // Header File For Standard Input/Output
#include <assert.h>
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#if defined(__APPLE__) && defined(__MACH__)
#include <OpenGL/gl.h> // Header File For The OpenGL32 Library
#include <OpenGL/glu.h> // Header File For The GLu32 Library
#elif defined(__DREAMCAST__)
#include <kos.h>
#include <GL/gl.h> // Header File For The OpenGL32 Library
#include <GL/glu.h> // Header File For The GLu32 Library
#include <GL/glkos.h>
#else
#include <GL/gl.h> // Header File For The OpenGL32 Library
#include <GL/glu.h> // Header File For The GLu32 Library
#endif
#define BOOL int
#define FALSE 0
#define TRUE 1
uint8_t* keys; // Array Used For The Keyboard Routine
BOOL active=TRUE; // Window Active Flag Set To TRUE By Default
BOOL fullscreen=FALSE; // Fullscreen Flag Set To Fullscreen Mode By Default
BOOL masking=TRUE; // Masking On/Off
BOOL mp; // M Pressed?
BOOL sp; // Space Pressed?
BOOL scene; // Which Scene To Draw
GLuint texture[5]; // Storage For Our Five Textures
GLuint loop; // Generic Loop Variable
GLfloat roll; // Rolling Texture
int LoadGLTextures() // Load Bitmaps And Convert To Textures
{
int Status=FALSE; // Status Indicator
Image TextureImage[5];
if ((ImageLoad(IMG_LOGO_PATH, &TextureImage[0])) && // Logo Texture
(ImageLoad(IMG_MASK1_PATH, &TextureImage[1])) && // First Mask
(ImageLoad(IMG_IMAGE1_PATH, &TextureImage[2])) && // First Image
(ImageLoad(IMG_MASK2_PATH, &TextureImage[3])) && // Second Mask
(ImageLoad(IMG_IMAGE2_PATH, &TextureImage[4]))) // Second Image
{
Status=TRUE; // Set The Status To TRUE
glGenTextures(5, &texture[0]); // Create Five Textures
for (loop=0; loop<5; loop++) // Loop Through All 5 Textures
{
glBindTexture(GL_TEXTURE_2D, texture[loop]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(
GL_TEXTURE_2D, 0, 3,
TextureImage[loop].sizeX,
TextureImage[loop].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[loop].data
);
}
}
return Status; // Return The Status
}
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); // Calculate Window Aspect Ratio
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
if (!LoadGLTextures()) // Jump To Texture Loading Routine
{
return FALSE; // If Texture Didn't Load Return FALSE
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glEnable(GL_DEPTH_TEST); // Enable Depth Testing
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glEnable(GL_TEXTURE_2D); // Enable 2D Texture Mapping
return TRUE; // Initialization Went OK
}
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The Modelview Matrix
glTranslatef(0.0f,0.0f,-2.0f); // Move Into The Screen 5 Units
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Logo Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(0.0f, -roll+0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(3.0f, -roll+0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(3.0f, -roll+3.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(0.0f, -roll+3.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
glEnable(GL_BLEND); // Enable Blending
glDisable(GL_DEPTH_TEST); // Disable Depth Testing
if (masking) // Is Masking Enabled?
{
glBlendFunc(GL_DST_COLOR,GL_ZERO); // Blend Screen Color With Zero (Black)
}
if (scene) // Are We Drawing The Second Scene?
{
glTranslatef(0.0f,0.0f,-1.0f); // Translate Into The Screen One Unit
glRotatef(roll*360,0.0f,0.0f,1.0f); // Rotate On The Z Axis 360 Degrees.
if (masking) // Is Masking On?
{
glBindTexture(GL_TEXTURE_2D, texture[3]); // Select The Second Mask Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
}
glBlendFunc(GL_ONE, GL_ONE); // Copy Image 2 Color To The Screen
glBindTexture(GL_TEXTURE_2D, texture[4]); // Select The Second Image Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
}
else // Otherwise
{
if (masking) // Is Masking On?
{
glBindTexture(GL_TEXTURE_2D, texture[1]); // Select The First Mask Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(roll+0.0f, 0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(roll+4.0f, 0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(roll+4.0f, 4.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(roll+0.0f, 4.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
}
glBlendFunc(GL_ONE, GL_ONE); // Copy Image 1 Color To The Screen
glBindTexture(GL_TEXTURE_2D, texture[2]); // Select The First Image Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(roll+0.0f, 0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(roll+4.0f, 0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(roll+4.0f, 4.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(roll+0.0f, 4.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
}
glEnable(GL_DEPTH_TEST); // Enable Depth Testing
glDisable(GL_BLEND); // Disable Blending
roll+=0.002f; // Increase Our Texture Roll Variable
if (roll>1.0f) // Is Roll Greater Than One
{
roll-=1.0f; // Subtract 1 From Roll
}
glKosSwapBuffers();
return TRUE; // Everything Went OK
}
int main(int argc, char *argv[])
{
BOOL done=FALSE; // Bool Variable To Exit Loop
glKosInit();
InitGL();
ReSizeGLScene(640, 480);
#ifdef __DREAMCAST__
maple_device_t* cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
assert(cont);
#endif
while(1) {
DrawGLScene();
#ifdef __DREAMCAST__
cont_state_t* state = (cont_state_t *)maple_dev_status(cont);
if((state->buttons & CONT_A) && !sp) {
sp = TRUE;
scene = !scene;
} else {
sp = FALSE;
}
if((state->buttons & CONT_B) && !mp) {
mp = TRUE;
masking = !masking;
} else {
mp = FALSE;
}
if(state->buttons & CONT_START) {
break;
}
#endif
}
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

View File

@ -1,29 +0,0 @@
TARGET = ortho2d.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -1,3 +1,7 @@
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glkos.h"
@ -35,6 +39,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -60,6 +81,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

View File

@ -1,29 +0,0 @@
TARGET = paletted.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

View File

@ -3,13 +3,22 @@
#include <stdlib.h>
#include <stdint.h>
#ifdef __DREAMCAST__
#include <kos.h>
#endif
#include "GL/gl.h"
#include "GL/glext.h"
#include "GL/glu.h"
#include "GL/glkos.h"
#ifdef __DREAMCAST__
extern uint8_t romdisk[];
KOS_INIT_ROMDISK(romdisk);
#define IMG_PATH "/rd/NeHe.tex"
#else
#define IMG_PATH "../samples/paletted/romdisk/NeHe.tex"
#endif
/* floats for x rotation, y rotation, z rotation */
float xrot, yrot, zrot;
@ -71,7 +80,7 @@ int LoadPalettedTex(const char* filename, Image* image) {
} palette_header;
fread(&palette_header, sizeof(palette_header), 1, filein);
image->palette = (unsigned int*) malloc(sizeof(unsigned int) * palette_header.numcolors);
image->palette = (char*) malloc(sizeof(unsigned int) * palette_header.numcolors);
image->palette_width = palette_header.numcolors;
fread(image->palette, sizeof(unsigned int), palette_header.numcolors, filein);
@ -107,7 +116,7 @@ void LoadGLTextures() {
exit(0);
}
if (!LoadPalettedTex("/rd/NeHe.tex", image1)) {
if (!LoadPalettedTex(IMG_PATH, image1)) {
exit(1);
}
@ -123,8 +132,10 @@ void LoadGLTextures() {
// 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
// border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, image1->width, image1->height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE_TWID_KOS, image1->data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, image1->width, image1->height, 0, GL_COLOR_INDEX8_TWID_KOS, GL_UNSIGNED_BYTE, image1->data);
glGenerateMipmapEXT(GL_TEXTURE_2D);
free(image1);
}
/* A general OpenGL initialization function. Sets all of the initial parameters. */
@ -161,6 +172,23 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef __DREAMCAST__
maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
/* The main drawing function. */
void DrawGLScene()
@ -232,6 +260,9 @@ int main(int argc, char **argv)
ReSizeGLScene(640, 480);
while(1) {
if(check_start())
break;
DrawGLScene();
}

Some files were not shown because too many files have changed in this diff Show More