Add vulkan renderer

Copied from vkQuake3 which is in turn based on Quake III Kenny Edition
This commit is contained in:
Trung Lê 2025-03-13 23:06:29 +11:00
parent c9697a0104
commit 15ff484715
No known key found for this signature in database
165 changed files with 110423 additions and 1 deletions

136
Makefile
View file

@ -46,6 +46,9 @@ endif
ifndef BUILD_RENDERER_OPENGL2
BUILD_RENDERER_OPENGL2=
endif
ifndef BUILD_RENDERER_VULKAN
BUILD_RENDERER_VULKAN=
endif
ifndef BUILD_AUTOUPDATER # DON'T build unless you mean to!
BUILD_AUTOUPDATER=0
endif
@ -264,6 +267,7 @@ SDIR=$(MOUNT_DIR)/server
RCOMMONDIR=$(MOUNT_DIR)/renderercommon
RGL1DIR=$(MOUNT_DIR)/renderergl1
RGL2DIR=$(MOUNT_DIR)/renderergl2
RVULKANDIR=$(MOUNT_DIR)/renderervk
CMDIR=$(MOUNT_DIR)/qcommon
SDLDIR=$(MOUNT_DIR)/sdl
ASMDIR=$(MOUNT_DIR)/asm
@ -1168,6 +1172,9 @@ ifneq ($(BUILD_CLIENT),0)
ifneq ($(BUILD_RENDERER_OPENGL2),0)
TARGETS += $(B)/renderer_opengl2_$(SHLIBNAME)
endif
ifneq ($(BUILD_RENDERER_VULKAN),0)
TARGETS += $(B)/renderer_vulkan_$(SHLIBNAME)
endif
else
ifneq ($(BUILD_RENDERER_OPENGL1),0)
TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT)
@ -1175,6 +1182,9 @@ ifneq ($(BUILD_CLIENT),0)
ifneq ($(BUILD_RENDERER_OPENGL2),0)
TARGETS += $(B)/$(CLIENTBIN)_opengl2$(FULLBINEXT)
endif
ifneq ($(BUILD_RENDERER_VULKAN),0)
TARGETS += $(B)/$(CLIENTBIN)_vulkan$(FULLBINEXT)
endif
endif
endif
@ -1642,6 +1652,7 @@ makedirs:
@$(MKDIR) $(B)/renderergl1
@$(MKDIR) $(B)/renderergl2
@$(MKDIR) $(B)/renderergl2/glsl
@$(MKDIR) $(B)/renderervk
@$(MKDIR) $(B)/ded
@$(MKDIR) $(B)/$(BASEGAME)/cgame
@$(MKDIR) $(B)/$(BASEGAME)/game
@ -1997,6 +2008,88 @@ else
endif
endif
Q3VKOBJ = \
$(B)/renderervk/matrix_multiplication.o \
$(B)/renderervk/tr_globals.o \
$(B)/renderervk/tr_cvar.o \
$(B)/renderervk/tr_animation.o \
$(B)/renderervk/tr_bsp.o \
$(B)/renderervk/tr_cmds.o \
$(B)/renderervk/tr_curve.o \
$(B)/renderervk/tr_fonts.o \
$(B)/renderervk/tr_image.o \
$(B)/renderervk/R_FindShader.o \
$(B)/renderervk/R_ListShader.o \
$(B)/renderervk/R_ImageProcess.o \
$(B)/renderervk/tr_init.o \
$(B)/renderervk/tr_light.o \
$(B)/renderervk/tr_main.o \
$(B)/renderervk/tr_marks.o \
$(B)/renderervk/tr_mesh.o \
$(B)/renderervk/tr_model.o \
$(B)/renderervk/tr_model_iqm.o \
$(B)/renderervk/RE_RegisterModel.o \
$(B)/renderervk/R_ModelBounds.o \
$(B)/renderervk/R_LoadMD3.o \
$(B)/renderervk/R_LoadMDR.o \
$(B)/renderervk/R_LerpTag.o \
$(B)/renderervk/tr_noise.o \
$(B)/renderervk/tr_scene.o \
$(B)/renderervk/tr_shade.o \
$(B)/renderervk/tr_shade_calc.o \
$(B)/renderervk/tr_shader.o \
$(B)/renderervk/tr_shadows.o \
$(B)/renderervk/tr_sky.o \
$(B)/renderervk/tr_surface.o \
$(B)/renderervk/tr_flares.o \
$(B)/renderervk/tr_fog.o \
$(B)/renderervk/tr_world.o \
$(B)/renderervk/vk_instance.o \
$(B)/renderervk/vk_init.o \
$(B)/renderervk/vk_cmd.o \
$(B)/renderervk/vk_image.o \
$(B)/renderervk/vk_image_sampler2.o \
$(B)/renderervk/vk_pipelines.o \
$(B)/renderervk/vk_frame.o \
$(B)/renderervk/vk_swapchain.o \
$(B)/renderervk/vk_screenshot.o \
$(B)/renderervk/vk_shade_geometry.o \
$(B)/renderervk/vk_depth_attachment.o \
\
$(B)/renderervk/vk_shaders.o \
$(B)/renderervk/multi_texture_clipping_plane_vert.o \
$(B)/renderervk/multi_texture_frag.o \
$(B)/renderervk/multi_texture_vert.o \
$(B)/renderervk/single_texture_clipping_plane_vert.o \
$(B)/renderervk/single_texture_frag.o \
$(B)/renderervk/single_texture_vert.o \
\
$(B)/renderervk/R_StretchRaw.o \
$(B)/renderervk/R_DebugGraphics.o \
$(B)/renderervk/RB_ShowImages.o \
$(B)/renderervk/RB_DrawNormals.o \
$(B)/renderervk/RB_DrawTris.o \
$(B)/renderervk/RB_SurfaceAnim.o \
$(B)/renderervk/tr_backend.o \
$(B)/renderervk/tr_Cull.o \
$(B)/renderervk/glConfig.o \
$(B)/renderervk/R_Parser.o \
$(B)/renderervk/R_PortalPlane.o \
$(B)/renderervk/R_PrintMat.o \
\
$(B)/renderervk/R_LoadImage2.o \
$(B)/renderervk/R_LoadImage.o \
$(B)/renderervk/R_ImageJPG.o \
$(B)/renderervk/R_ImageTGA.o \
$(B)/renderervk/R_ImagePNG.o \
$(B)/renderervk/R_ImageBMP.o \
$(B)/renderervk/R_ImagePCX.o \
\
$(B)/renderervk/ref_import.o \
$(B)/renderervk/render_export.o \
\
$(B)/renderervk/vk_create_window_SDL.o
Q3R2OBJ = \
$(B)/renderergl2/tr_animation.o \
$(B)/renderergl2/tr_backend.o \
@ -2116,6 +2209,11 @@ ifneq ($(USE_RENDERER_DLOPEN), 0)
$(B)/renderergl1/puff.o \
$(B)/renderergl1/q_math.o \
$(B)/renderergl1/tr_subs.o
Q3VKOBJ += \
$(B)/renderergl1/q_shared.o \
$(B)/renderergl1/puff.o \
$(B)/renderergl1/q_math.o
endif
ifneq ($(USE_INTERNAL_JPEG),0)
@ -2426,6 +2524,11 @@ $(B)/renderer_opengl2_$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \
$(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS)
$(B)/renderer_vulkan_$(SHLIBNAME): $(Q3VKOBJ) $(JPGOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3VKOBJ) $(JPGOBJ) \
$(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS)
else
$(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(Q3ROBJ) $(JPGOBJ) $(LIBSDLMAIN)
$(echo_cmd) "LD $@"
@ -2438,6 +2541,12 @@ $(B)/$(CLIENTBIN)_opengl2$(FULLBINEXT): $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(J
$(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(NOTSHLIBLDFLAGS) \
-o $@ $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \
$(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS)
$(B)/$(CLIENTBIN)_vulkan$(FULLBINEXT): $(Q3OBJ) $(Q3VKOBJ) $(JPGOBJ) $(LIBSDLMAIN)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(NOTSHLIBLDFLAGS) \
-o $@ $(Q3OBJ) $(Q3VKOBJ) $(JPGOBJ) \
$(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS)
endif
ifneq ($(strip $(LIBSDLMAIN)),)
@ -2967,6 +3076,24 @@ $(B)/renderergl2/%.o: $(RCOMMONDIR)/%.c
$(B)/renderergl2/%.o: $(RGL2DIR)/%.c
$(DO_REF_CC)
$(B)/renderervk/%.o: $(CMDIR)/%.c
$(DO_REF_CC)
$(B)/renderervk/%.o: $(SDLDIR)/%.c
$(DO_REF_CC)
$(B)/renderervk/%.o: $(JPDIR)/%.c
$(DO_REF_CC)
$(B)/renderervk/%.o: $(RCOMMONDIR)/%.c
$(DO_REF_CC)
$(B)/renderervk/%.o: $(RVULKANDIR)/%.c
$(DO_REF_CC)
$(B)/renderervk/%.o: $(MOUNT_DIR)/renderervk/shaders/Compiled/%.c
$(DO_REF_CC)
$(B)/ded/%.o: $(ASMDIR)/%.s
$(DO_AS)
@ -3104,7 +3231,7 @@ $(B)/$(CLIENTBIN)-config.json: $(WEBDIR)/client-config.json
# MISC
#############################################################################
OBJ = $(Q3OBJ) $(Q3ROBJ) $(Q3R2OBJ) $(Q3DOBJ) $(JPGOBJ) \
OBJ = $(Q3OBJ) $(Q3ROBJ) $(Q3R2OBJ) $(Q3VKOBJ) $(Q3DOBJ) $(JPGOBJ) \
$(MPGOBJ) $(Q3GOBJ) $(Q3CGOBJ) $(MPCGOBJ) $(Q3UIOBJ) $(MPUIOBJ) \
$(MPGVMOBJ) $(Q3GVMOBJ) $(Q3CGVMOBJ) $(MPCGVMOBJ) $(Q3UIVMOBJ) $(MPUIVMOBJ)
TOOLSOBJ = $(LBURGOBJ) $(Q3CPPOBJ) $(Q3RCCOBJ) $(Q3LCCOBJ) $(Q3ASMOBJ)
@ -3131,6 +3258,9 @@ ifneq ($(BUILD_CLIENT),0)
ifneq ($(BUILD_RENDERER_OPENGL2),0)
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_opengl2_$(SHLIBNAME) $(COPYBINDIR)/renderer_opengl2_$(SHLIBNAME)
endif
ifneq ($(BUILD_RENDERER_VULKAN),0)
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_vulkan_$(SHLIBNAME) $(COPYBINDIR)/renderer_vulkan_$(SHLIBNAME)
endif
else
ifneq ($(BUILD_RENDERER_OPENGL1),0)
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)$(FULLBINEXT)
@ -3138,6 +3268,9 @@ ifneq ($(BUILD_CLIENT),0)
ifneq ($(BUILD_RENDERER_OPENGL2),0)
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)_opengl2$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)_opengl2$(FULLBINEXT)
endif
ifneq ($(BUILD_RENDERER_VULKAN),0)
$(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)_vulkan$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)_vulkan$(FULLBINEXT)
endif
endif
endif
@ -3185,6 +3318,7 @@ clean2:
@rm -f $(OBJ_D_FILES)
@rm -f $(STRINGOBJ)
@rm -f $(TARGETS)
@rm -rf $(Q3VKOBJ)
@rm -f $(GENERATEDTARGETS)
toolsclean: toolsclean-debug toolsclean-release

View file

@ -147,6 +147,7 @@ Makefile.local:
USE_RENDERER_DLOPEN - build and use the renderer in a library
BUILD_RENDERER_OPENGL1 build the opengl1 client / renderer library
BUILD_RENDERER_OPENGL2 build the opengl2 client / renderer library
BUILD_RENDERER_VULKAN build the vulkan client / renderer library
USE_YACC - use yacc to update code/tools/lcc/lburg/gram.c
BASEGAME - rename 'baseq3'
BASEGAME_CFLAGS - custom CFLAGS for basegame
@ -199,6 +200,12 @@ set using command line arguments:
ioquake3 +set cl_renderer opengl2 +set r_preferOpenGLES 1
# Vulkan support
The vulkan rendender can be enabled by:
ioquake3 +set cl_renderer vulkan
# Console
## New cvars

View file

@ -0,0 +1,43 @@
#include "tr_backend.h"
#include "vk_shade_geometry.h"
#include "tr_globals.h"
#include "vk_pipelines.h"
/*
================
Draws vertex normals for debugging
================
*/
void RB_DrawNormals (shaderCommands_t* pTess, int numVertexes )
{
// VULKAN
// int numVertexes = tess.numVertexes;
vec4_t xyz[SHADER_MAX_VERTEXES];
memcpy(xyz, pTess->xyz, numVertexes * sizeof(vec4_t));
memset(pTess->svars.colors, tr.identityLightByte, SHADER_MAX_VERTEXES * sizeof(color4ub_t));
int i = 0;
while (i < numVertexes)
{
int count = numVertexes - i;
if (count >= SHADER_MAX_VERTEXES/2 - 1)
count = SHADER_MAX_VERTEXES/2 - 1;
int k;
for (k = 0; k < count; k++)
{
VectorCopy(xyz[i + k], pTess->xyz[2*k]);
VectorMA(xyz[i + k], 2, pTess->normal[i + k], pTess->xyz[2*k + 1]);
}
pTess->numVertexes = 2 * count;
pTess->numIndexes = 0;
vk_UploadXYZI(pTess->xyz, pTess->numVertexes, NULL, 0);
updateMVP(backEnd.viewParms.isPortal, backEnd.projection2D, getptr_modelview_matrix());
vk_shade_geometry(g_stdPipelines.normals_debug_pipeline, VK_FALSE, DEPTH_RANGE_ZERO, VK_FALSE);
i += count;
}
}

View file

@ -0,0 +1,8 @@
#ifndef RB_SHOW_NORMALS_H_
#define RB_SHOW_NORMALS_H_
struct shaderCommands_s;
void RB_DrawNormals (struct shaderCommands_s* input , int numVertexes );
#endif

View file

@ -0,0 +1,30 @@
#include "RB_DrawTris.h"
#include "tr_globals.h"
#include "vk_shade_geometry.h"
#include "vk_pipelines.h"
#include "tr_backend.h"
/*
================
Draws triangle outlines for debugging
================
*/
void RB_DrawTris (shaderCommands_t * pInput)
{
if (vk.features.fillModeNonSolid == VK_FALSE) {
static qboolean printed = qfalse;
if (!printed) {
ri.Printf(PRINT_WARNING, "RB_ShowTris: fillModeNonSolid not supported.\n");
printed = qtrue;
}
return;
}
updateCurDescriptor( tr.whiteImage->descriptor_set, 0);
// VULKAN
memset(pInput->svars.colors, 255, pInput->numVertexes * 4 );
VkPipeline pipeline = backEnd.viewParms.isMirror ? g_stdPipelines.tris_mirror_debug_pipeline : g_stdPipelines.tris_debug_pipeline;
vk_shade_geometry(pipeline, VK_FALSE, DEPTH_RANGE_ZERO, VK_TRUE);
}

View file

@ -0,0 +1,7 @@
#ifndef RB_DRAWTRIS_H_
#define RB_DRAWTRIS_H_
struct shaderCommands_s;
void RB_DrawTris (struct shaderCommands_s *input);
#endif

View file

@ -0,0 +1,85 @@
#include "tr_backend.h"
#include "vk_shade_geometry.h"
#include "vk_pipelines.h"
#include "glConfig.h"
/*
===============
Draw all the images to the screen, on top of whatever was there.
This is used to test for texture thrashing.
Also called by RE_EndRegistration
===============
*/
// TODO: move glConfig retated stuff to glConfig.c,
void RB_ShowImages(image_t ** const pImg, unsigned int N)
{
backEnd.projection2D = qtrue;
const float black[4] = {0, 0, 0, 1};
vk_clearColorAttachments(black);
int width;
int height;
R_GetWinResolution(&width, &height);
const float w = width / 20;
const float h = height / 15;
tess.numIndexes = 6;
tess.numVertexes = 4;
uint32_t i;
for (i = 0 ; i < N; ++i)
{
//image_t* image = tr.images[i];
float x = i % 20 * w;
float y = i / 20 * h;
tess.indexes[0] = 0;
tess.indexes[1] = 1;
tess.indexes[2] = 2;
tess.indexes[3] = 0;
tess.indexes[4] = 2;
tess.indexes[5] = 3;
tess.xyz[0][0] = x;
tess.xyz[0][1] = y;
tess.xyz[1][0] = x + w;
tess.xyz[1][1] = y;
tess.xyz[2][0] = x + w;
tess.xyz[2][1] = y + h;
tess.xyz[3][0] = x;
tess.xyz[3][1] = y + h;
tess.svars.texcoords[0][0][0] = 0;
tess.svars.texcoords[0][0][1] = 0;
tess.svars.texcoords[0][1][0] = 1;
tess.svars.texcoords[0][1][1] = 0;
tess.svars.texcoords[0][2][0] = 1;
tess.svars.texcoords[0][2][1] = 1;
tess.svars.texcoords[0][3][0] = 0;
tess.svars.texcoords[0][3][1] = 1;
memset( tess.svars.colors, 255, tess.numVertexes * 4 );
updateCurDescriptor( pImg[i]->descriptor_set, 0);
vk_UploadXYZI(tess.xyz, 4, tess.indexes, 6);
// updateMVP(backEnd.viewParms.isPortal, backEnd.projection2D, getptr_modelview_matrix());
updateMVP( 0 , 1, getptr_modelview_matrix());
vk_shade_geometry(g_stdPipelines.images_debug_pipeline, VK_FALSE, DEPTH_RANGE_NORMAL, VK_TRUE);
}
tess.numIndexes = 0;
tess.numVertexes = 0;
}

View file

@ -0,0 +1,6 @@
#ifndef RB_SHOW_IMAGES_H_
#define RB_SHOW_IMAGES_H_
void RB_ShowImages(image_t ** const pImg, unsigned int N);
#endif

View file

@ -0,0 +1,137 @@
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#include "tr_globals.h"
#include "RB_SurfaceAnim.h"
#include "tr_backend.h"
void RB_MDRSurfaceAnim( mdrSurface_t *surface )
{
int j, k;
float backlerp;
mdrBone_t bones[MDR_MAX_BONES], *bonePtr;
// don't lerp if lerping off, or this is the only frame, or the last frame...
if (backEnd.currentEntity->e.oldframe == backEnd.currentEntity->e.frame)
{
backlerp = 0; // if backlerp is 0, lerping is off and frontlerp is never used
}
else
{
backlerp = backEnd.currentEntity->e.backlerp;
}
mdrHeader_t* header = (mdrHeader_t *)((unsigned char *)surface + surface->ofsHeader);
int frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
mdrFrame_t* frame = (mdrFrame_t *)((byte *)header + header->ofsFrames + backEnd.currentEntity->e.frame * frameSize );
mdrFrame_t* oldFrame = (mdrFrame_t *)((byte *)header + header->ofsFrames + backEnd.currentEntity->e.oldframe * frameSize );
RB_CHECKOVERFLOW( surface->numVerts, surface->numTriangles * 3 );
int* triangles = (int *) ((byte *)surface + surface->ofsTriangles);
int indexes = surface->numTriangles * 3;
int baseIndex = tess.numIndexes;
int baseVertex = tess.numVertexes;
// Set up all triangles.
for (j = 0 ; j < indexes ; j++)
{
tess.indexes[baseIndex + j] = baseVertex + triangles[j];
}
tess.numIndexes += indexes;
//
// lerp all the needed bones
//
if ( !backlerp )
{
// no lerping needed
bonePtr = frame->bones;
}
else
{
bonePtr = bones;
int nBones = header->numBones;
int n;
float tmp;
for ( n = 0 ; n < nBones; n++ )
{
tmp = frame->bones[n].matrix[0][0];
bones[n].matrix[0][0] = tmp + backlerp * (oldFrame->bones[n].matrix[0][0] - tmp);
tmp = frame->bones[n].matrix[0][1];
bones[n].matrix[0][1] = tmp + backlerp * (oldFrame->bones[n].matrix[0][1] - tmp);
tmp = frame->bones[n].matrix[0][2];
bones[n].matrix[0][2] = tmp + backlerp * (oldFrame->bones[n].matrix[0][2] - tmp);
tmp = frame->bones[n].matrix[0][3];
bones[n].matrix[0][3] = tmp + backlerp * (oldFrame->bones[n].matrix[0][3] - tmp);
tmp = frame->bones[n].matrix[1][0];
bones[n].matrix[1][0] = tmp + backlerp * (oldFrame->bones[n].matrix[1][0] - tmp);
tmp = frame->bones[n].matrix[1][1];
bones[n].matrix[1][1] = tmp + backlerp * (oldFrame->bones[n].matrix[1][1] - tmp);
tmp = frame->bones[n].matrix[1][2];
bones[n].matrix[1][2] = tmp + backlerp * (oldFrame->bones[n].matrix[1][2] - tmp);
tmp = frame->bones[n].matrix[1][3];
bones[n].matrix[1][3] = tmp + backlerp * (oldFrame->bones[n].matrix[1][3] - tmp);
tmp = frame->bones[n].matrix[2][0];
bones[n].matrix[2][0] = tmp + backlerp * (oldFrame->bones[n].matrix[2][0] - tmp);
tmp = frame->bones[n].matrix[2][1];
bones[n].matrix[2][1] = tmp + backlerp * (oldFrame->bones[n].matrix[2][1] - tmp);
tmp = frame->bones[n].matrix[2][2];
bones[n].matrix[2][2] = tmp + backlerp * (oldFrame->bones[n].matrix[2][2] - tmp);
tmp = frame->bones[n].matrix[2][3];
bones[n].matrix[2][3] = tmp + backlerp * (oldFrame->bones[n].matrix[2][3] - tmp);
}
}
//
// deform the vertexes by the lerped bones
//
mdrVertex_t* v = (mdrVertex_t *) ((unsigned char *)surface + surface->ofsVerts);
int numVerts = surface->numVerts;
for( j = 0; j < numVerts; j++ )
{
float tempVert[3] = {0, 0, 0};
float tempNormal[3] = {0, 0, 0};
mdrWeight_t *w = v->weights;
for ( k = 0 ; k < v->numWeights ; k++, w++ )
{
mdrBone_t* bone = bonePtr + w->boneIndex;
tempVert[0] += w->boneWeight * ( DotProduct( bone->matrix[0], w->offset ) + bone->matrix[0][3] );
tempVert[1] += w->boneWeight * ( DotProduct( bone->matrix[1], w->offset ) + bone->matrix[1][3] );
tempVert[2] += w->boneWeight * ( DotProduct( bone->matrix[2], w->offset ) + bone->matrix[2][3] );
tempNormal[0] += w->boneWeight * DotProduct( bone->matrix[0], v->normal );
tempNormal[1] += w->boneWeight * DotProduct( bone->matrix[1], v->normal );
tempNormal[2] += w->boneWeight * DotProduct( bone->matrix[2], v->normal );
}
tess.xyz[baseVertex + j][0] = tempVert[0];
tess.xyz[baseVertex + j][1] = tempVert[1];
tess.xyz[baseVertex + j][2] = tempVert[2];
tess.normal[baseVertex + j][0] = tempNormal[0];
tess.normal[baseVertex + j][1] = tempNormal[1];
tess.normal[baseVertex + j][2] = tempNormal[2];
tess.texCoords[baseVertex + j][0][0] = v->texCoords[0];
tess.texCoords[baseVertex + j][0][1] = v->texCoords[1];
//supress GGC strict-alisaing warnning
{
mdrWeight_t* pTmp = &v->weights[v->numWeights];
v = (mdrVertex_t *) pTmp;
}
}
tess.numVertexes += surface->numVerts;
}

View file

@ -0,0 +1,5 @@
#ifndef RB_SURFACEANIM_H
#define RB_SURFACEANIM_H
#include "tr_model.h"
void RB_MDRSurfaceAnim( mdrSurface_t *surface );
#endif

148
code/renderervk/README.md Normal file
View file

@ -0,0 +1,148 @@
# vulkan backend info
* codes in this dir is "borrow" from https://github.com/kennyalive/Quake-III-Arena-Kenny-Edition, I convert cpp to c so that it can compile.
* vulkan forder is copied form vulkan sdk, not all items in it is used, it need clean.
* I am a naive programmer, need help, doc and instructions.
# Rendering
## General setup.
Single command buffer that records all the commands. Single render pass which specifies color and depth-stencil attachment.
Stencil buffer is used to render Q3's stencil shadows (cg\_shadows=2).
## Geometry.
Quake 3 renderer prepares geometry data for each draw call in tess.xyz and tess.indexes arrays.
OpenGL backend calls qglDrawElements to feed this geometry to the GPU.
Vulkan backend appends this data to geometry buffers that are bound to host visible memory chunk.
At the end of the frame when command buffer is submitted to the queue the geometry buffers contain all the geometry data to render the frame.
Typically up to 500Kb of vertex data is copied to the vertex buffer and up to 100Kb of index data is copied to the index buffer per frame.
## Descriptor sets.
For each image used by the renderer separate descriptor set is created.
Each descriptor set contains single descriptor (combined image sampler).
For each draw call either one or two (if lightmap is available) descriptor sets are bound.
Descriptor sets are updated only once during initialization.
There are no descriptor set updates during frame.
## Per-primitive uniform data.
Vulkan guarantees that minimum size of push constants range is at least 128 bytes.
To render ordinary view we use 64 bytes to specify mvp transform.
For portaled/mirrored views additional 64 byte are used to specify eye transform and clipping plane.
Pipeline layout. 2 sets + 128 bytes push constant range.
## Pipelines.
Standard pipelines are created when renderer starts.
They are used for skybox rendering, fog/dynamic light effects, shadow volumes and various debug features.
Map specific pipelines are created as part of parsing Q3 shaders and are created during map load.
For each Q3 shader we create three pipelines: one pipeline to render regular view and two additional pipelines for portal and mirror views.
## Shaders.
Emulate corresponding fixed-function functionality.
Vertex shaders are boring with the only thing to mention that for portaled/mirrored views
we additionally compute distance to the clipping plane.
Fragment shaders do one or two texture lookups and modulate the results by the color.
## Draw calls.
vkCmdDrawIndexed is used to draw geometry in most cases. Additionally there are few debug features that use vkCmdDraw to convey unindexed vertexes.
## Code
vk.h provides interface that brings Vulkan support to Q3 renderer.
The interface is quite concise and consists of a dozen of functions that can be divided into 3 categories:
initialization functions, resource management functions and rendering setup functions.
### Initialization:
* vk\_initialize : initialize Vulkan backend
* vk\_shutdown : shutdown Vulkan backend
### Resource management:
* images: vk\_create\_image/vk\_upload\_image\_data
* descriptor sets: vk\_update\_descriptor\_set
* samplers: vk\_find\_sampler
* pipelines: vk\_find\_pipeline
### Rendering setup:
* vk\_clear\_attachments : clears framebuffer¡¯s attachments.
* vk\_bind\_geometry : is called when we start drawing new geometry.
* vk\_shade\_geometry : is called to shade geometry specified with vk\_bind\_geometry. Can be called multiple times for Q3's multi-stage shaders.
* vk\_begin\_frame/vk\_end\_frame : frame setup.
* vk\_read\_pixels : takes a screenshot.
### about turn the intensity/gamma of the drawing wondow
* use r\_gamma in the pulldown window, which nonlinearly correct the image before the uploading to GPU.
`\r_gamma 1.5` then `vid_restart`
* you can also use r\_intensity which turn the intensity linearly.
```
# 1.5 ~ 2.0 give acceptable result
$ \r_intensity 1.8
$ \vid_restart
```
* but why, because original gamma setting program turn the light by setting entire destop window.
which works on newer computer on the market
but not works on some machine. it is buggy and embarrasing when program abnormal quit or stall.
### new cmd
* pipelineList: list the pipeline we have created;
* gpuMem: image memmory allocated on GPU;
* printOR: print the value of backend.or;
* displayResoList: list of the display resolution you monitor supported
For example:
```
$ \displayResoList
Mode 0: 320x240
Mode 1: 400x300
Mode 2: 512x384
Mode 3: 640x480 (480p)
Mode 4: 800x600
Mode 5: 960x720
Mode 6: 1024x768
Mode 7: 1152x864
Mode 8: 1280x1024
Mode 9: 1600x1200
Mode 10: 2048x1536
Mode 11: 856x480
Mode 12: 1280x720 (720p)
Mode 13: 1280x768
Mode 14: 1280x800
Mode 15: 1280x960
Mode 16: 1360x768
Mode 17: 1366x768
Mode 18: 1360x1024
Mode 19: 1400x1050
Mode 20: 1400x900
Mode 21: 1600x900
Mode 22: 1680x1050
Mode 23: 1920x1080 (1080p)
Mode 24: 1920x1200
Mode 25: 1920x1440
Mode 26: 2560x1080
Mode 27: 2560x1600
Mode 28: 3840x2160 (4K)
$ \r_mode 12
$ \vid_restart
```
### TODO:
* get cpu, gpu, memory usage

View file

@ -0,0 +1,142 @@
#include "tr_local.h"
#include "tr_model.h"
#include "tr_globals.h"
#include "ref_import.h"
typedef struct
{
char *ext;
qhandle_t (* ModelLoader)( const char * , model_t * );
} modelExtToLoaderMap_t;
// Note that the ordering indicates the order of preference used
// when there are multiple models of different formats available
static const modelExtToLoaderMap_t modelLoaders[ ] =
{
{ "md3", R_RegisterMD3 },
{ "mdr", R_RegisterMDR },
{ "iqm", R_RegisterIQM }
};
static const uint32_t numModelLoaders = ARRAY_LEN(modelLoaders);
/*
====================
Loads in a model for the given name
Zero will be returned if the model fails to load.
An entry will be retained for failed models as an
optimization to prevent disk rescanning if they are
asked for again.
====================
*/
qhandle_t RE_RegisterModel( const char *name )
{
ri.Printf( PRINT_ALL, "RegisterModel: %s. \n", name);
qboolean orgNameFailed = qfalse;
int orgLoader = -1;
if ( !name || !name[0] ) {
ri.Printf( PRINT_WARNING, "RE_RegisterModel: NULL name\n" );
return 0;
}
if ( strlen( name ) >= MAX_QPATH ) {
ri.Printf( PRINT_WARNING, "Model name exceeds MAX_QPATH\n" );
return 0;
}
//
// search the currently loaded models
//
qhandle_t hModel;
for ( hModel = 1; hModel < tr.numModels; hModel++ )
{
if ( 0 == strcmp( tr.models[hModel]->name, name ) )
{
if( tr.models[hModel]->type == MOD_BAD )
{
ri.Printf( PRINT_WARNING, "tr.models[%d]->type = MOD_BAD \n", hModel);
return 0;
}
return hModel;
}
}
// allocate a new model_t
ri.Printf( PRINT_ALL, "Allocate Memory for %s. \n", name);
model_t* mod = ri.Hunk_Alloc( sizeof( model_t ), h_low );
// only set the name after the model has been successfully loaded
strncpy(mod->name, name, MAX_QPATH);
mod->index = tr.numModels;
mod->type = MOD_BAD;
mod->numLods = 0;
tr.models[tr.numModels] = mod;
if ( ++tr.numModels > MAX_MOD_KNOWN )
{
ri.Printf(PRINT_WARNING, "RE_RegisterModel: MAX_MOD_KNOWN.\n");
}
// load the files
const char* dot = strrchr(name, '.');
if(dot != NULL)
{
if( (dot[1] == 'm') && (dot[2] == 'd') && (dot[3] == '3') )
{
hModel = R_RegisterMD3(name, mod);
}
else if( (dot[1] == 'm') && (dot[2] == 'd') && (dot[3] == 'r') )
{
hModel = R_RegisterMDR(name, mod);
}
else if( (dot[1] == 'i') && (dot[2] == 'q') && (dot[3] == 'm') )
{
hModel = R_RegisterIQM(name, mod);
}
else
{
ri.Printf( PRINT_WARNING, " %s format not support now. \n ", name);
}
}
else
{
ri.Printf( PRINT_WARNING, "RegisterModel: %s without extention. "
" Try and find a suitable match using all the model formats supported\n", name);
uint32_t i;
for( i = 0; i < numModelLoaders; i++ )
{
if (i == orgLoader)
continue;
char altName[ MAX_QPATH * 2 ] = {0};
snprintf( altName, sizeof (altName), "%s.%s", name, modelLoaders[ i ].ext );
// Load
hModel = modelLoaders[ i ].ModelLoader( altName, mod );
if( hModel )
{
if( orgNameFailed )
{
ri.Printf( PRINT_ALL, "WARNING: %s not present, using %s instead\n",
name, altName );
}
break;
}
}
}
return hModel;
}

View file

@ -0,0 +1,109 @@
#include "tr_globals.h"
#include "vk_shade_geometry.h"
#include "vk_instance.h"
#include "vk_image.h"
#include "vk_pipelines.h"
#include "tr_cvar.h"
#include "tr_backend.h"
#include "ref_import.h"
#include "matrix_multiplication.h"
void R_DebugPolygon( int color, int numPoints, float *points )
{
if (numPoints < 3 || numPoints >= SHADER_MAX_VERTEXES/2)
return;
int i;
// In Vulkan we don't have GL_POLYGON + GLS_POLYMODE_LINE equivalent,
// so we use lines to draw polygon outlines.This approach has additional
// implication that we need to do manual backface culling to reject outlines
// that belong to back facing polygons. The code assumes that polygons are convex.
// Backface culling.
float pa[3], pb[3], p[3];
const float* m = getptr_modelview_matrix();
// transform to eye space
Vec3Transform(points, m, pa);
Vec3Transform(&points[3], m, pb);
VectorSubtract(pb, pa, p);
float n[3];
for (i = 2; i < numPoints; i++)
{
Vec3Transform(&points[3*i], m, pb);
float q[3];
VectorSubtract(pb, pa, q);
CrossProduct(q, p, n);
if (VectorLength(n) > 1e-5)
break;
}
if (DotProduct(n, pa) >= 0)
return; // discard backfacing polygon
// Solid shade.
for (i = 0; i < numPoints; i++)
{
VectorCopy(&points[3*i], tess.xyz[i]);
tess.svars.colors[i][0] = (color&1) ? 255 : 0;
tess.svars.colors[i][1] = (color&2) ? 255 : 0;
tess.svars.colors[i][2] = (color&4) ? 255 : 0;
tess.svars.colors[i][3] = 255;
}
tess.numVertexes = numPoints;
tess.numIndexes = 0;
for (i = 1; i < numPoints - 1; i++)
{
tess.indexes[tess.numIndexes + 0] = 0;
tess.indexes[tess.numIndexes + 1] = i;
tess.indexes[tess.numIndexes + 2] = i + 1;
tess.numIndexes += 3;
}
vk_UploadXYZI(tess.xyz, tess.numVertexes, tess.indexes, tess.numIndexes);
updateMVP(backEnd.viewParms.isPortal, backEnd.projection2D, getptr_modelview_matrix());
vk_shade_geometry(g_stdPipelines.surface_debug_pipeline_solid, VK_FALSE, DEPTH_RANGE_NORMAL, VK_TRUE);
// Outline.
memset(tess.svars.colors, tr.identityLightByte, numPoints * 2 * sizeof(color4ub_t));
for (i = 0; i < numPoints; i++)
{
VectorCopy(&points[3*i], tess.xyz[2*i]);
VectorCopy(&points[3*((i + 1) % numPoints)], tess.xyz[2*i + 1]);
}
tess.numVertexes = numPoints * 2;
tess.numIndexes = 0;
vk_UploadXYZI(tess.xyz, tess.numVertexes, tess.indexes, 0);
updateMVP(backEnd.viewParms.isPortal, backEnd.projection2D, getptr_modelview_matrix());
vk_shade_geometry(g_stdPipelines.surface_debug_pipeline_outline, VK_FALSE, DEPTH_RANGE_ZERO, VK_FALSE);
tess.numVertexes = 0;
}
/*
====================
R_DebugGraphics
Visualization aid for movement clipping debugging
====================
*/
void R_DebugGraphics( void )
{
// the render thread can't make callbacks to the main thread
if ( tr.registered ) {
R_IssueRenderCommands( qfalse );
}
updateCurDescriptor( tr.whiteImage->descriptor_set, 0);
ri.CM_DrawDebugSurface( R_DebugPolygon );
}

View file

@ -0,0 +1,5 @@
#ifndef R_DEBUG_GRAPHICS_H_
#define R_DEBUG_GRAPHICS_H_
void R_DebugGraphics(void);
#endif

View file

@ -0,0 +1,678 @@
#include "tr_local.h"
#include "vk_image.h"
#include "tr_cvar.h"
#include "ref_import.h"
#include "R_PrintMat.h"
#include "R_Parser.h"
#include "tr_globals.h"
#include "tr_shader.h"
#define MAX_SHADERTEXT_HASH 2048
static char** shaderTextHashTable[MAX_SHADERTEXT_HASH] ={ 0 };
#define FILE_HASH_SIZE 1024
static shader_t* hashTable[FILE_HASH_SIZE] = {0};
static char *s_shaderText = NULL;
/*
================
return a hash value for the filename
================
*/
static int generateHashValue( const char *fname, const int size )
{
int i = 0;
long hash = 0;
while (fname[i] != '\0')
{
char letter = tolower(fname[i]);
if (letter =='.') break; // don't include extension
if (letter =='\\') letter = '/'; // damn path names
if (letter == PATH_SEP) letter = '/'; // damn path names
hash+=(long)(letter)*(i+119);
i++;
}
hash = (hash ^ (hash >> 10) ^ (hash >> 20));
hash &= (size-1);
return hash;
}
void R_ClearShaderHashTable()
{
memset(hashTable, 0, sizeof(hashTable));
}
/*
====================
FindShaderInShaderText
Scans the combined text description of all the shader files for the given
shader name. If found, it will return a valid shader, return NULL if not found.
=====================
*/
static char* FindShaderInShaderText( const char *shadername )
{
// ri.Printf( PRINT_ALL, "FindShaderInShaderText: %s\n", shadername);
int hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH);
int i;
for (i = 0; shaderTextHashTable[hash][i]; i++)
{
char* p = shaderTextHashTable[hash][i];
char* token = R_ParseExt(&p, qtrue);
if ( !Q_stricmp( token, shadername ) )
{
return p;
}
}
char* p = s_shaderText;
if ( !p ) {
return NULL;
}
// look for label
while ( 1 )
{
char* token = R_ParseExt( &p, qtrue );
if( token[0] == 0 )
{
break;
}
if ( !Q_stricmp( token, shadername ) )
{
return p;
}
else
{
// skip the definition, tr_common
// -> R_SkipBracedSection ?
SkipBracedSection( &p , 0);
}
}
return NULL;
}
/*
===============
R_FindShader
Will always return a valid shader, but it might be the
default shader if the real one can't be found.
In the interest of not requiring an explicit shader text entry to
be defined for every single image used in the game, three default
shader behaviors can be auto-created for any image:
If lightmapIndex == LIGHTMAP_NONE, then the image will have
dynamic diffuse lighting applied to it, as apropriate for most
entity skin surfaces.
If lightmapIndex == LIGHTMAP_2D, then the image will be used
for 2D rendering unless an explicit shader is found
If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use
the vertex rgba modulate values, as apropriate for misc_model
pre-lit surfaces.
Other lightmapIndex values will have a lightmap stage created
and src*dest blending applied with the texture, as apropriate for
most world construction surfaces.
===============
*/
extern void setDefaultShader(void);
shader_t* R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage )
{
char strippedName[MAX_QPATH] = {0};
if ( name == NULL )
{
ri.Printf( PRINT_WARNING, "Find Shader: name = NULL\n");
return tr.defaultShader;
}
// use (fullbright) vertex lighting if the bsp file doesn't have lightmaps
if ( (lightmapIndex >= 0) && (lightmapIndex >= tr.numLightmaps) )
{
lightmapIndex = LIGHTMAP_BY_VERTEX;
}
else if ( lightmapIndex < LIGHTMAP_2D )
{
// negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex])
ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex );
lightmapIndex = LIGHTMAP_BY_VERTEX;
}
R_StripExtension(name, strippedName, sizeof(strippedName));
int hash = generateHashValue(strippedName, FILE_HASH_SIZE);
//
// see if the shader is already loaded
//
{
shader_t* sh = hashTable[hash];
while ( sh )
{
// NOTE: if there was no shader or image available with the name strippedName
// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
// have to check all default shaders otherwise for every call to R_findShader
// with that same strippedName a new default shader is created.
if ( ( 0 == Q_stricmp(sh->name, strippedName) ) && (sh->lightmapIndex == lightmapIndex || sh->defaultShader) )
{
// match found
return sh;
}
sh = sh->next;
}
}
R_SetTheShader( strippedName, lightmapIndex );
//
// attempt to define shader from an explicit parameter file
//
{
char* shaderText = FindShaderInShaderText( strippedName );
if ( shaderText )
{
// enable this when building a pak file to get a global list
// of all explicit shaders
if ( r_printShaders->integer ) {
ri.Printf( PRINT_ALL, "*SHADER* %s\n", name );
}
if ( !ParseShader( &shaderText ) )
{
// had errors, so use default shader
R_SetDefaultShader( );
ri.Printf( PRINT_WARNING, "ParseShader: %s had errors\n", strippedName );
}
return FinishShader();
}
}
// if not defined in the in-memory shader descriptions,
// look for a single supported image file
/*
char fileName[128] = {0};
{
qboolean ptExist = qfalse;
int i = 0;
while(name[i] != '\0')
{
fileName[i] = name[i];
if(fileName[i] == '.')
{
ptExist = qtrue;
}
i++;
}
// if path doesn't have an extension, then append
// the specified one (which should include the .)
if(ptExist == qtrue)
fileName[i] = '\0';
else
{
fileName[i++] = '.';
fileName[i++] = 't';
fileName[i++] = 'g';
fileName[i++] = 'a';
fileName[i] = '\0';
}
}
*/
image_t* image = R_FindImageFile( name, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP );
if(image != NULL)
{
// create the default shading commands
R_CreateDefaultShadingCmds(name, image);
}
else
{
setDefaultShader();
}
return FinishShader();
}
/*
====================
This is the exported shader entry point for the rest of the system
It will always return an index that will be valid.
This should really only be used for explicit shaders, because there is no
way to ask for different implicit lighting modes (vertex, lightmap, etc)
====================
*/
qhandle_t RE_RegisterShader( const char *name )
{
if ( strlen( name ) >= MAX_QPATH ) {
ri.Printf(PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
return 0;
}
shader_t* sh = R_FindShader( name, LIGHTMAP_2D, qtrue );
// we want to return 0 if the shader failed to
// load for some reason, but R_FindShader should
// still keep a name allocated for it, so if
// something calls RE_RegisterShader again with
// the same name, we don't try looking for it again
if ( sh->defaultShader ) {
return 0;
}
return sh->index;
}
/*
====================
RE_RegisterShaderNoMip
For menu graphics that should never be picmiped
====================
*/
qhandle_t RE_RegisterShaderNoMip( const char *name )
{
if ( strlen( name ) >= MAX_QPATH ) {
ri.Printf(PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
return 0;
}
shader_t* sh = R_FindShader( name, LIGHTMAP_2D, qfalse );
// we want to return 0 if the shader failed to
// load for some reason, but R_FindShader should
// still keep a name allocated for it, so if
// something calls RE_RegisterShader again with
// the same name, we don't try looking for it again
if ( sh->defaultShader ) {
return 0;
}
return sh->index;
}
qhandle_t R_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage)
{
int hash = generateHashValue(name, FILE_HASH_SIZE);
//
// see if the shader is already loaded
//
shader_t* sh = hashTable[hash];
while(sh)
{
// NOTE: if there was no shader or image available with the name strippedName
// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
// have to check all default shaders otherwise for every call to R_FindShader
// with that same strippedName a new default shader is created.
if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
// index by name
!Q_stricmp(sh->name, name)) {
// match found
return sh->index;
}
sh = sh->next;
}
R_SetTheShader( name, lightmapIndex );
//
// create the default shading commands
//
R_CreateDefaultShadingCmds(name, image);
sh = FinishShader();
return sh->index;
}
/*
====================
ScanAndLoadShaderFiles
Finds and loads all .shader files, combining them into
a single large text block that can be scanned for shader names
=====================
*/
static void BuildSingleLargeBuffer(char* buffers[], const int nShaderFiles, const int sum)
{
// build single large buffer
s_shaderText = ri.Hunk_Alloc( sum + nShaderFiles*2, h_low );
s_shaderText[ 0 ] = '\0';
char* textEnd = s_shaderText;
int n = nShaderFiles - 1;
// free in reverse order, so the temp files are all dumped
for ( n = nShaderFiles - 1; n >= 0 ; n-- )
{
if ( buffers[n] )
{
strcat( textEnd, buffers[n] );
strcat( textEnd, "\n" );
textEnd += strlen(buffers[n]) + 1;
ri.FS_FreeFile( buffers[n] );
}
}
}
static void Shader_DoSimpleCheck(char* name, char* p)
{
char* pBuf = p;
R_BeginParseSession(name);
while(1)
{
char* token = R_ParseExt(&p, qtrue);
if(0 == *token)
break;
char shaderName[64]={0};
strncpy(shaderName, token, sizeof(shaderName));
int shaderLine = R_GetCurrentParseLine();
token = R_ParseExt(&p, qtrue);
if(token[0] != '{' || token[1] != '\0')
{
ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace",
name, shaderName, shaderLine);
if (token[0])
{
ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, R_GetCurrentParseLine());
}
ri.Printf(PRINT_WARNING, ".\n");
ri.FS_FreeFile(pBuf);
pBuf = NULL;
break;
}
if(!SkipBracedSection(&p, 1))
{
ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n",
name, shaderName, shaderLine);
ri.FS_FreeFile(pBuf);
pBuf = NULL;
break;
}
}
}
static void SetShaderTextHashTableSizes( void )
{
int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH];
memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
int size = 0;
char* p = s_shaderText;
// look for shader names
while ( 1 )
{
char* token = R_ParseExt( &p, qtrue );
if ( token[0] == 0 )
{
break;
}
int hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
shaderTextHashTableSizes[hash]++;
size++;
SkipBracedSection(&p, 0);
}
size += MAX_SHADERTEXT_HASH;
char* hashMem = (char*)ri.Hunk_Alloc( size * sizeof(char *), h_low );
int i;
for (i = 0; i < MAX_SHADERTEXT_HASH; i++)
{
shaderTextHashTable[i] = (char **) hashMem;
hashMem += (shaderTextHashTableSizes[i] + 1) * sizeof(char *);
}
memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
p = s_shaderText;
// look for shader names
while ( 1 )
{
char* oldp = p;
char* token = R_ParseExt( &p, qtrue );
if ( token[0] == 0 ) {
break;
}
int hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;
SkipBracedSection(&p, 0);
}
}
#define MAX_SHADER_FILES 4096
void ScanAndLoadShaderFiles( void )
{
ri.Printf( PRINT_ALL, "ScanAndLoadShaderFiles\n" );
char *buffers[MAX_SHADER_FILES] = {0};
int numShaderFiles = 0;
// scan for shader files
char** shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles );
if ( !shaderFiles || !numShaderFiles )
{
ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" );
return;
}
if ( numShaderFiles > MAX_SHADER_FILES ) {
numShaderFiles = MAX_SHADER_FILES;
ri.Printf( PRINT_WARNING, "numShaderFiles > MAX_SHADER_FILES\n" );
}
// load and parse shader files
long sum = 0;
int i;
for ( i = 0; i < numShaderFiles; i++ )
{
char filename[128] = {0};
snprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
ri.Printf( PRINT_ALL, "...loading '%s'\n", filename );
long summand = ri.FS_ReadFile( filename, (void**)&buffers[i] );
if ( !buffers[i] )
ri.Error( ERR_DROP, "Couldn't load %s", filename );
// Do a simple check on the shader structure in that file
// to make sure one bad shader file cannot fuck up all other shaders.
Shader_DoSimpleCheck(filename, buffers[i]);
if (buffers[i])
sum += summand;
}
// build single large buffer
BuildSingleLargeBuffer(buffers, numShaderFiles, sum);
R_Compress( s_shaderText );
// free up memory
ri.FS_FreeFileList( shaderFiles );
SetShaderTextHashTableSizes();
return;
}
/*
====================
RE_RegisterShader
This is the exported shader entry point for the rest of the system
It will always return an index that will be valid.
This should really only be used for explicit shaders, because there is no
way to ask for different implicit lighting modes (vertex, lightmap, etc)
====================
*/
void RE_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset)
{
shader_t* sh2 = tr.defaultShader;
//R_FindShaderByName( newShaderName );
{
char strippedName2[MAX_QPATH];
R_StripExtension( newShaderName, strippedName2, sizeof(strippedName2) );
int hash2 = generateHashValue(strippedName2, FILE_HASH_SIZE);
// see if the shader is already loaded
shader_t* pSh = hashTable[hash2];
while ( pSh )
{
// NOTE: if there was no shader or image available with the name strippedName
// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
// have to check all default shaders otherwise for every call to R_findShader
// with that same strippedName a new default shader is created.
if (Q_stricmp(pSh->name, strippedName2) == 0)
{
// match found
sh2 = pSh;
break;
}
pSh=pSh->next;
}
if (sh2 == tr.defaultShader)
{
qhandle_t h;
//h = RE_RegisterShaderLightMap(newShaderName, 0);
pSh = R_FindShader( newShaderName, 0, qtrue );
if ( pSh->defaultShader )
{
h = 0;
}
else
{
h = pSh->index;
}
sh2 = R_GetShaderByHandle(h);
if( (sh2 == tr.defaultShader) || (sh2 == NULL) )
{
ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", newShaderName );
}
}
}
char strippedName[MAX_QPATH];
R_StripExtension(shaderName, strippedName, sizeof(strippedName));
int hash = generateHashValue(strippedName, FILE_HASH_SIZE);
shader_t* sh = hashTable[hash];
// remap all the shaders with the given name
// even tho they might have different lightmaps
while( sh )
{
if (Q_stricmp(sh->name, strippedName) == 0)
{
if (sh != sh2)
{
sh->remappedShader = sh2;
}
else
{
sh->remappedShader = NULL;
}
}
sh = sh->next;
}
if (timeOffset)
{
sh2->timeOffset = atof(timeOffset);
}
}
void R_UpdateShaderHashTable(shader_t* newShader)
{
int hash = generateHashValue(newShader->name, FILE_HASH_SIZE);
newShader->next = hashTable[hash];
hashTable[hash] = newShader;
}

View file

@ -0,0 +1,238 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "ref_import.h"
#include "image_loader.h"
typedef struct
{
char id[2];
unsigned fileSize;
unsigned reserved0;
unsigned bitmapDataOffset;
unsigned bitmapHeaderSize;
unsigned width;
unsigned height;
unsigned short planes;
unsigned short bitsPerPixel;
unsigned compression;
unsigned bitmapDataSize;
unsigned hRes;
unsigned vRes;
unsigned colors;
unsigned importantColors;
unsigned char palette[256][4];
} BMPHeader_t;
void R_LoadBMP( const char *name, byte **pic, int *width, int *height )
{
int columns, rows;
unsigned numPixels;
byte *pixbuf;
int row, column;
byte *buf_p;
byte *end;
char * buffer;
int length;
BMPHeader_t bmpHeader;
byte *bmpRGBA;
*pic = NULL;
if(width)
*width = 0;
if(height)
*height = 0;
//
// load the file
//
length = ri.FS_ReadFile( name, (void**)&buffer );
if (!buffer || length < 0) {
return;
}
if (length < 54)
{
ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name );
}
buf_p = (unsigned char*)buffer;
end = (unsigned char*)buffer + length;
bmpHeader.id[0] = *buf_p++;
bmpHeader.id[1] = *buf_p++;
bmpHeader.fileSize = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.width = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.height = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.planes = LittleShort( * ( short * ) buf_p );
buf_p += 2;
bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
buf_p += 2;
bmpHeader.compression = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.hRes = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.vRes = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.colors = LittleLong( * ( int * ) buf_p );
buf_p += 4;
bmpHeader.importantColors = LittleLong( * ( int * ) buf_p );
buf_p += 4;
if ( bmpHeader.bitsPerPixel == 8 )
{
if (buf_p + sizeof(bmpHeader.palette) > end)
ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name );
memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
}
if ((unsigned char*)buffer + bmpHeader.bitmapDataOffset > end)
{
ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)", name );
}
buf_p = (unsigned char*)buffer + bmpHeader.bitmapDataOffset;
if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
{
ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)", name );
}
if ( bmpHeader.fileSize != length )
{
ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)", bmpHeader.fileSize, length, name );
}
if ( bmpHeader.compression != 0 )
{
ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)", name );
}
if ( bmpHeader.bitsPerPixel < 8 )
{
ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)", name );
}
switch ( bmpHeader.bitsPerPixel )
{
case 8:
case 16:
case 24:
case 32:
break;
default:
ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'", bmpHeader.bitsPerPixel, name );
break;
}
columns = bmpHeader.width;
rows = bmpHeader.height;
if ( rows < 0 )
rows = -rows;
numPixels = columns * rows;
if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF
|| ((numPixels * 4) / columns) / 4 != rows)
{
ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size", name);
}
if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end)
{
ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)", name);
}
if ( width )
*width = columns;
if ( height )
*height = rows;
bmpRGBA = ri.Malloc( numPixels * 4 );
*pic = bmpRGBA;
for ( row = rows-1; row >= 0; row-- )
{
pixbuf = bmpRGBA + row*columns*4;
for ( column = 0; column < columns; column++ )
{
unsigned char red, green, blue, alpha;
int palIndex;
unsigned short shortPixel;
switch ( bmpHeader.bitsPerPixel )
{
case 8:
palIndex = *buf_p++;
*pixbuf++ = bmpHeader.palette[palIndex][2];
*pixbuf++ = bmpHeader.palette[palIndex][1];
*pixbuf++ = bmpHeader.palette[palIndex][0];
*pixbuf++ = 0xff;
break;
case 16:
shortPixel = * ( unsigned short * ) pixbuf;
pixbuf += 2;
*pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;
*pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;
*pixbuf++ = ( shortPixel & ( 31 ) ) << 3;
*pixbuf++ = 0xff;
break;
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alpha = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alpha;
break;
}
}
}
ri.FS_FreeFile( buffer );
}

View file

@ -0,0 +1,473 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include <setjmp.h>
#include "tr_local.h"
#include "ref_import.h"
/*
* Include file for users of JPEG library.
* You will need to have included system headers that define at least
* the typedefs FILE and size_t before you can include jpeglib.h.
* (stdio.h is sufficient on ANSI-conforming systems.)
* You may also wish to include "jerror.h".
*/
#ifdef USE_INTERNAL_JPEG
# define JPEG_INTERNALS
#endif
#include <jpeglib.h>
#ifndef USE_INTERNAL_JPEG
# if JPEG_LIB_VERSION < 80 && !defined(MEM_SRCDST_SUPPORTED)
# error Need system libjpeg >= 80 or jpeg_mem_ support
# endif
#endif
/* Catching errors, as done in libjpeg's example.c */
typedef struct q_jpeg_error_mgr_s
{
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
} q_jpeg_error_mgr_t;
static void R_JPGErrorExit(j_common_ptr cinfo)
{
char buffer[JMSG_LENGTH_MAX];
/* cinfo->err really points to a q_jpeg_error_mgr_s struct, so coerce pointer */
q_jpeg_error_mgr_t *jerr = (q_jpeg_error_mgr_t *)cinfo->err;
(*cinfo->err->format_message) (cinfo, buffer);
ri.Printf(PRINT_ALL, "Error: %s", buffer);
/* Return control to the setjmp point */
longjmp(jerr->setjmp_buffer, 1);
}
static void R_JPGOutputMessage(j_common_ptr cinfo)
{
char buffer[JMSG_LENGTH_MAX];
/* Create the message */
(*cinfo->err->format_message) (cinfo, buffer);
/* Send it to stderr, adding a newline */
ri.Printf(PRINT_ALL, "%s\n", buffer);
}
void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *height)
{
/* This struct contains the JPEG decompression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
*/
struct jpeg_decompress_struct cinfo = {NULL};
/* We use our private extension JPEG error handler.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
/* This struct represents a JPEG error handler. It is declared separately
* because applications often want to supply a specialized error handler
* (see the second half of this file for an example). But here we just
* take the easy way out and use the standard error handler, which will
* print a message on stderr and call exit() if compression fails.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
q_jpeg_error_mgr_t jerr;
/* More stuff */
JSAMPARRAY buffer; /* Output row buffer */
unsigned int row_stride; /* physical row width in output buffer */
unsigned int pixelcount, memcount;
unsigned int sindex, dindex;
byte *out;
int len;
char * fbuffer;
byte *buf;
/* In this example we want to open the input file before doing anything else,
* so that the setjmp() error recovery below can assume the file is open.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to read binary files.
*/
len = ri.FS_ReadFile ( filename, (void**)&fbuffer);
if (!fbuffer || len < 0) {
return;
}
/* Step 1: allocate and initialize JPEG decompression object */
/* We have to set up the error handler first, in case the initialization
* step fails. (Unlikely, but it could happen if you are out of memory.)
* This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo.
*/
cinfo.err = jpeg_std_error(&jerr.pub);
cinfo.err->error_exit = R_JPGErrorExit;
cinfo.err->output_message = R_JPGOutputMessage;
/* Establish the setjmp return context for R_JPGErrorExit to use. */
if (setjmp(jerr.setjmp_buffer))
{
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_decompress(&cinfo);
ri.FS_FreeFile(fbuffer);
/* Append the filename to the error for easier debugging */
ri.Printf(PRINT_ALL, ", loading file %s\n", filename);
return;
}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_mem_src(&cinfo, (unsigned char*)fbuffer, len);
/* Step 3: read file parameters with jpeg_read_header() */
(void) jpeg_read_header(&cinfo, TRUE);
/* We can ignore the return value from jpeg_read_header since
* (a) suspension is not possible with the stdio data source, and
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
* See libjpeg.doc for more info.
*/
/* Step 4: set parameters for decompression */
/*
* Make sure it always converts images to RGB color space. This will
* automatically convert 8-bit greyscale images to RGB as well.
*/
cinfo.out_color_space = JCS_RGB;
/* Step 5: Start decompressor */
(void) jpeg_start_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* We may need to do some setup of our own at this point before reading
* the data. After jpeg_start_decompress() we have the correct scaled
* output image dimensions available, as well as the output colormap
* if we asked for color quantization.
* In this example, we need to make an output work buffer of the right size.
*/
/* JSAMPLEs per row in output buffer */
pixelcount = cinfo.output_width * cinfo.output_height;
if(!cinfo.output_width || !cinfo.output_height
|| ((pixelcount * 4) / cinfo.output_width) / 4 != cinfo.output_height
|| pixelcount > 0x1FFFFFFF || cinfo.output_components != 3
)
{
// Free the memory to make sure we don't leak memory
ri.FS_FreeFile (fbuffer);
jpeg_destroy_decompress(&cinfo);
ri.Error(ERR_DROP, "LoadJPG: %s has an invalid image format: %dx%d*4=%d, components: %d", filename,
cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components);
}
memcount = pixelcount * 4;
row_stride = cinfo.output_width * cinfo.output_components;
out = ri.Malloc(memcount);
*width = cinfo.output_width;
*height = cinfo.output_height;
/* Step 6: while (scan lines remain to be read) */
/* jpeg_read_scanlines(...); */
/* Here we use the library's state variable cinfo.output_scanline as the
* loop counter, so that we don't have to keep track ourselves.
*/
while (cinfo.output_scanline < cinfo.output_height) {
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
buf = ((out+(row_stride*cinfo.output_scanline)));
buffer = &buf;
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
}
buf = out;
// Expand from RGB to RGBA
sindex = pixelcount * cinfo.output_components;
dindex = memcount;
do
{
buf[--dindex] = 255;
buf[--dindex] = buf[--sindex];
buf[--dindex] = buf[--sindex];
buf[--dindex] = buf[--sindex];
} while(sindex);
*pic = out;
/* Step 7: Finish decompression */
jpeg_finish_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
/* After finish_decompress, we can close the input file.
* Here we postpone it until after no more JPEG errors are possible,
* so as to simplify the setjmp error logic above. (Actually, I don't
* think that jpeg_destroy can do an error exit, but why assume anything...)
*/
ri.FS_FreeFile (fbuffer);
/* At this point you may want to check to see whether any corrupt-data
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
*/
/* And we're done! */
}
/* Expanded data destination object for stdio output */
typedef struct {
struct jpeg_destination_mgr pub; /* public fields */
byte* outfile; /* target stream */
int size;
} my_destination_mgr;
typedef my_destination_mgr * my_dest_ptr;
/*
* Initialize destination --- called by jpeg_start_compress
* before any data is actually written.
*/
static void
init_destination (j_compress_ptr cinfo)
{
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
dest->pub.next_output_byte = dest->outfile;
dest->pub.free_in_buffer = dest->size;
}
/*
* Empty the output buffer --- called whenever buffer fills up.
*
* In typical applications, this should write the entire output buffer
* (ignoring the current state of next_output_byte & free_in_buffer),
* reset the pointer & count to the start of the buffer, and return TRUE
* indicating that the buffer has been dumped.
*
* In applications that need to be able to suspend compression due to output
* overrun, a FALSE return indicates that the buffer cannot be emptied now.
* In this situation, the compressor will return to its caller (possibly with
* an indication that it has not accepted all the supplied scanlines). The
* application should resume compression after it has made more room in the
* output buffer. Note that there are substantial restrictions on the use of
* suspension --- see the documentation.
*
* When suspending, the compressor will back up to a convenient restart point
* (typically the start of the current MCU). next_output_byte & free_in_buffer
* indicate where the restart point will be if the current call returns FALSE.
* Data beyond this point will be regenerated after resumption, so do not
* write it out when emptying the buffer externally.
*/
static boolean
empty_output_buffer (j_compress_ptr cinfo)
{
my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
jpeg_destroy_compress(cinfo);
// Make crash fatal or we would probably leak memory.
ri.Error(ERR_FATAL, "Output buffer for encoded JPEG image has insufficient size of %d bytes",
dest->size);
return FALSE;
}
/*
* Terminate destination --- called by jpeg_finish_compress
* after all data has been written. Usually needs to flush buffer.
*
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
* application must deal with any cleanup that should happen even
* for error exit.
*/
static void term_destination(j_compress_ptr cinfo)
{
}
/*
* Prepare for output to a stdio stream.
* The caller must have already opened the stream, and is responsible
* for closing it after finishing compression.
*/
static void
jpegDest (j_compress_ptr cinfo, byte* outfile, int size)
{
my_dest_ptr dest;
/* The destination object is made permanent so that multiple JPEG images
* can be written to the same file without re-executing jpeg_stdio_dest.
* This makes it dangerous to use this manager and a different destination
* manager serially with the same JPEG object, because their private object
* sizes may be different. Caveat programmer.
*/
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(my_destination_mgr));
}
dest = (my_dest_ptr) cinfo->dest;
dest->pub.init_destination = init_destination;
dest->pub.empty_output_buffer = empty_output_buffer;
dest->pub.term_destination = term_destination;
dest->outfile = outfile;
dest->size = size;
}
/*
=================
SaveJPGToBuffer
Encodes JPEG from image in image_buffer and writes to buffer.
Expects RGB input data
=================
*/
size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
int image_width, int image_height, byte *image_buffer, int padding)
{
struct jpeg_compress_struct cinfo;
q_jpeg_error_mgr_t jerr;
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
my_dest_ptr dest;
int row_stride; /* physical row width in image buffer */
size_t outcount;
/* Step 1: allocate and initialize JPEG compression object */
cinfo.err = jpeg_std_error(&jerr.pub);
cinfo.err->error_exit = R_JPGErrorExit;
cinfo.err->output_message = R_JPGOutputMessage;
/* Establish the setjmp return context for R_JPGErrorExit to use. */
if (setjmp(jerr.setjmp_buffer))
{
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object and return.
*/
jpeg_destroy_compress(&cinfo);
ri.Printf(PRINT_ALL, "\n");
return 0;
}
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
jpegDest(&cinfo, buffer, bufSize);
/* Step 3: set parameters for compression */
cinfo.image_width = image_width; /* image width and height, in pixels */
cinfo.image_height = image_height;
cinfo.input_components = 3; /* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
/* If quality is set high, disable chroma subsampling */
if (quality >= 85) {
cinfo.comp_info[0].h_samp_factor = 1;
cinfo.comp_info[0].v_samp_factor = 1;
}
/* Step 4: Start compressor */
jpeg_start_compress(&cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) */
/* jpeg_write_scanlines(...); */
row_stride = image_width * cinfo.input_components + padding; /* JSAMPLEs per row in image_buffer */
while (cinfo.next_scanline < cinfo.image_height) {
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
row_pointer[0] = &image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
dest = (my_dest_ptr) cinfo.dest;
outcount = dest->size - dest->pub.free_in_buffer;
/* Step 7: release JPEG compression object */
jpeg_destroy_compress(&cinfo);
/* And we're done! */
return outcount;
}
void RE_SaveJPG(char * filename, int quality, int image_width, int image_height, byte *image_buffer, int padding)
{
byte *out;
size_t bufSize;
bufSize = image_width * image_height * 3;
out = ri.Hunk_AllocateTempMemory(bufSize);
bufSize = RE_SaveJPGToBuffer(out, bufSize, quality, image_width, image_height, image_buffer, padding);
ri.FS_WriteFile(filename, out, bufSize);
ri.Hunk_FreeTempMemory(out);
}

View file

@ -0,0 +1,7 @@
#ifndef R_IMAGEJPG_H_
#define R_IMAGEJPG_H_
void RE_SaveJPG(char * filename, int quality, int image_width, int image_height, unsigned char *image_buffer, int padding);
size_t RE_SaveJPGToBuffer(unsigned char *buffer, size_t bufSize, int quality, int image_width, int image_height, unsigned char *image_buffer, int padding);
#endif

View file

@ -0,0 +1,170 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
2008 Ludwig Nussel
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "ref_import.h"
#include "image_loader.h"
/*
========================================================================
PCX files are used for 8 bit images
========================================================================
*/
typedef struct {
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
unsigned short hscreensize, vscreensize;
char filler[54];
char data[];
} pcx_t;
void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
{
char* raw;
unsigned char dataByte = 0, runLength = 0;
unsigned char *out, *pix;
unsigned short w, h;
unsigned char *pic8;
unsigned char *palette;
int i;
unsigned size = 0;
if (width)
*width = 0;
if (height)
*height = 0;
*pic = NULL;
//
// load the file
//
int len = ri.FS_ReadFile( filename, (void**)&raw );
if (!raw || len < 0) {
return;
}
if((unsigned)len < sizeof(pcx_t))
{
ri.Printf (PRINT_ALL, "PCX truncated: %s\n", filename);
ri.FS_FreeFile (raw);
return;
}
//
// parse the PCX file
//
pcx_t* pcx = (pcx_t *)raw;
unsigned char* end = (unsigned char*)raw+len;
w = LittleShort(pcx->xmax)+1;
h = LittleShort(pcx->ymax)+1;
size = w*h;
if (pcx->manufacturer != 0x0a
|| pcx->version != 5
|| pcx->encoding != 1
|| pcx->color_planes != 1
|| pcx->bits_per_pixel != 8
|| w >= 1024
|| h >= 1024)
{
ri.Printf (PRINT_ALL, "Bad or unsupported pcx file %s (%dx%d@%d)\n", filename, w, h, pcx->bits_per_pixel);
return;
}
pix = pic8 = ri.Malloc ( size );
raw = pcx->data;
// FIXME: should use bytes_per_line but original q3 didn't do that either
while(pix < pic8+size)
{
if(runLength > 0) {
*pix++ = dataByte;
--runLength;
continue;
}
if((unsigned char*)raw+1 > end)
break;
dataByte = *raw++;
if((dataByte & 0xC0) == 0xC0)
{
if((unsigned char*)raw+1 > end)
break;
runLength = dataByte & 0x3F;
dataByte = *raw++;
}
else
runLength = 1;
}
if(pix < pic8+size)
{
ri.Printf (PRINT_ALL, "PCX file truncated: %s\n", filename);
ri.FS_FreeFile (pcx);
ri.Free (pic8);
}
if ((byte*)raw-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c)
{
ri.Printf (PRINT_ALL, "PCX missing palette: %s\n", filename);
ri.FS_FreeFile (pcx);
ri.Free (pic8);
return;
}
palette = end-768;
pix = out = ri.Malloc(4 * size );
for (i = 0 ; i < size ; i++)
{
unsigned char p = pic8[i];
pix[0] = palette[p*3];
pix[1] = palette[p*3 + 1];
pix[2] = palette[p*3 + 2];
pix[3] = 255;
pix += 4;
}
if (width)
*width = w;
if (height)
*height = h;
*pic = out;
ri.FS_FreeFile (pcx);
ri.Free (pic8);
}

2483
code/renderervk/R_ImagePNG.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,534 @@
#include "tr_cvar.h"
#include "ref_import.h"
#include "vk_image.h"
#include "R_ImageProcess.h"
static unsigned char s_intensitytable[256];
static unsigned char s_gammatable[256];
/*
void R_GammaCorrect(unsigned char* buffer, const unsigned int Size)
{
unsigned int i;
for( i = 0; i < Size; i++ )
{
buffer[i] = s_gammatable[buffer[i]];
}
}
*/
void R_SetColorMappings( void )
{
int i, j;
int inf;
int shift = 0;
for (i = 0; i < 255; i++)
{
s_intensitytable[i] = s_gammatable[i] = i;
}
float g = r_gamma->value;
for ( i = 0; i < 256; i++ ) {
if ( g == 1 ) {
inf = i;
} else {
inf = 255 * pow ( i/255.0f, 1.0f / g ) + 0.5f;
}
inf <<= shift;
if (inf < 0) {
inf = 0;
}
else if (inf > 255) {
inf = 255;
}
s_gammatable[i] = inf;
}
if ( r_intensity->value <= 1 ) {
ri.Cvar_Set( "r_intensity", "1" );
}
for (i=0 ; i<256 ; i++)
{
j = i * r_intensity->value;
if (j > 255) {
j = 255;
}
s_intensitytable[i] = j;
}
}
/*
================
Scale up the pixel values in a texture to increase the lighting range
================
*/
void R_LightScaleTexture (unsigned char* dst, unsigned char* in, unsigned int nBytes)
{
unsigned int i;
if ( 0 )
{
for (i=0; i<nBytes; i+=4)
{
unsigned int n1 = i + 1;
unsigned int n2 = i + 2;
unsigned int n3 = i + 3;
dst[i] = s_gammatable[in[i]];
dst[n1] = s_gammatable[in[n1]];
dst[n2] = s_gammatable[in[n2]];
dst[n3] = in[n3];
}
}
else
{
for (i=0; i<nBytes; i+=4)
{
unsigned int n1 = i + 1;
unsigned int n2 = i + 2;
unsigned int n3 = i + 3;
dst[i] = s_gammatable[s_intensitytable[in[i]]];
dst[n1] = s_gammatable[s_intensitytable[in[n1]]];
dst[n2] = s_gammatable[s_intensitytable[in[n2]]];
dst[n3] = in[n3];
}
}
}
//////////////////////////////////////////////////////////////////////
//
// MIP maps
//
//////////////////////////////////////////////////////////////////////
// In computer graphics, mipmaps (also MIP maps) or pyramids are pre-calculated,
// optimized sequences of images, each of which is a progressively lower resolution
// representation of the same image. The height and width of each image, or level,
// in the mipmap is a power of two smaller than the previous level.
// Mipmaps do not have to be square. They are intended to increase rendering speed
// and reduce aliasing artifacts.
// A high-resolution mipmap image is used for high-density samples, such as for
// objects close to the camera. Lower-resolution images are used as the object
// appears farther away.
// This is a more efficient way of downfiltering (minifying) a texture than
// sampling all texels in the original texture that would contribute to a
// screen pixel; it is faster to take a constant number of samples from the
// appropriately downfiltered textures. Mipmaps are widely used in 3D computer games.
// The letters "MIP" in the name are an acronym of the Latin phrase multum in parvo,
// meaning "much in little".Since mipmaps, by definition, are pre-allocated,
// additional storage space is required to take advantage of them.
// Mipmap textures are used in 3D scenes to decrease the time required to
// render a scene. They also improve the scene's realism.
// mip-mapping of 1/3 more memory per texture.
/*
==================
R_BlendOverTexture
Apply a color blend over a set of pixels
==================
*/
void R_BlendOverTexture(unsigned char* data, const uint32_t pixelCount, uint32_t l)
{
uint32_t i;
static const unsigned char mipBlendColors[16][4] =
{
{0,0,0,0},
{255,0,0,128},
{0,255,0,128},
{0,0,255,128},
{255,0,0,128},
{0,255,0,128},
{0,0,255,128},
{255,0,0,128},
{0,255,0,128},
{0,0,255,128},
{255,0,0,128},
{0,255,0,128},
{0,0,255,128},
{255,0,0,128},
{0,255,0,128},
{0,0,255,128},
};
const unsigned int alpha = mipBlendColors[l][3];
const unsigned int inverseAlpha = 255 - alpha;
const unsigned int bR = mipBlendColors[l][0] * alpha;
const unsigned int bG = mipBlendColors[l][1] * alpha;
const unsigned int bB = mipBlendColors[l][2] * alpha;
for ( i = 0; i < pixelCount; i++, data+=4 )
{
data[0] = ( data[0] * inverseAlpha + bR ) >> 9;
data[1] = ( data[1] * inverseAlpha + bG ) >> 9;
data[2] = ( data[2] * inverseAlpha + bB ) >> 9;
}
}
/*
================
R_MipMap
Operates in place, quartering the size of the texture, no error checking
================
*/
void R_MipMap(const unsigned char* in, uint32_t width, uint32_t height, unsigned char* out)
{
if ( (width == 1) && (height == 1) )
{
out[0] = in[0];
return;
}
uint32_t i;
const unsigned int row = width * 4;
width >>= 1;
height >>= 1;
if ( (width == 0) || (height == 0) )
{
width += height; // get largest
for (i=0; i<width; i++, out+=4, in+=8 )
{
out[0] = ( in[0] + in[4] )>>1;
out[1] = ( in[1] + in[5] )>>1;
out[2] = ( in[2] + in[6] )>>1;
out[3] = ( in[3] + in[7] )>>1;
}
}
else
{
for (i=0; i<height; i++, in+=row)
{
uint32_t j;
for (j=0; j<width; j++, out+=4, in+=8)
{
out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2;
out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2;
out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2;
out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2;
}
}
}
}
/*
================
R_MipMap2
Operates in place, quartering the size of the texture
Proper linear filter, no error checking
================
*/
void R_MipMap2(const unsigned char* in, uint32_t inWidth, uint32_t inHeight, unsigned char* out)
{
int i, j;
if ( (inWidth == 1) && (inHeight == 1) )
{
out[0] = in[0];
return;
}
//ri.Printf (PRINT_ALL, "\n---R_MipMap2---\n");
// Not run time funs, can be used for best view effects
unsigned int outWidth = inWidth >> 1;
unsigned int outHeight = inHeight >> 1;
unsigned int nBytes = outWidth * outHeight * 4;
unsigned char * temp = (unsigned char *)malloc( nBytes );
const unsigned int inWidthMask = inWidth - 1;
const unsigned int inHeightMask = inHeight - 1;
for ( i = 0 ; i < outHeight ; i++ )
{
for ( j = 0 ; j < outWidth ; j++ )
{
unsigned int outIndex = i * outWidth + j;
unsigned int k;
for ( k = 0 ; k < 4 ; k++ )
{
unsigned int r0 = ((i*2-1) & inHeightMask) * inWidth;
unsigned int r1 = ((i*2 ) & inHeightMask) * inWidth;
unsigned int r2 = ((i*2+1) & inHeightMask) * inWidth;
unsigned int r3 = ((i*2+2) & inHeightMask) * inWidth;
unsigned int c0 = ((j*2-1) & inWidthMask);
unsigned int c1 = ((j*2 ) & inWidthMask);
unsigned int c2 = ((j*2+1) & inWidthMask);
unsigned int c3 = ((j*2+2) & inWidthMask);
unsigned int total =
1 * in[(r0 + c0) * 4 + k] +
2 * in[(r0 + c1) * 4 + k] +
2 * in[(r0 + c2) * 4 + k] +
1 * in[(r0 + c3) * 4 + k] +
2 * in[(r1 + c0) * 4 + k] +
4 * in[(r1 + c1) * 4 + k] +
4 * in[(r1 + c2) * 4 + k] +
2 * in[(r1 + c3) * 4 + k] +
2 * in[(r2 + c0) * 4 + k] +
4 * in[(r2 + c1) * 4 + k] +
4 * in[(r2 + c2) * 4 + k] +
2 * in[(r2 + c3) * 4 + k] +
1 * in[(r3 + c0) * 4 + k] +
2 * in[(r3 + c1) * 4 + k] +
2 * in[(r3 + c2) * 4 + k] +
1 * in[(r3 + c3) * 4 + k] ;
temp[4*outIndex + k] = total / 36;
}
}
}
memcpy( out, temp, nBytes );
free( temp );
}
/*
================
Used to resample images in a more general than quartering fashion.
This will only be filtered properly if the resampled size
is greater than half the original size.
If a larger shrinking is needed, use the mipmap function before or after.
================
*/
void ResampleTexture(unsigned char * pOut, const unsigned int inwidth, const unsigned int inheight,
const unsigned char *pIn, const unsigned int outwidth, const unsigned int outheight)
{
unsigned int i, j;
unsigned int p1[2048], p2[2048];
// printf("inwidth: %d \t outwidth: %d \n", inwidth, outwidth);
unsigned int fracstep = (inwidth << 16)/outwidth;
unsigned int frac1 = fracstep>>2;
unsigned int frac2 = 3*(fracstep>>2);
for(i=0; i<outwidth; i++)
{
p1[i] = 4*(frac1>>16);
frac1 += fracstep;
p2[i] = 4*(frac2>>16);
frac2 += fracstep;
}
for (i=0; i<outheight; i++)
{
const unsigned char* inrow1 = pIn + 4 * inwidth * (unsigned int)((i+0.25)*inheight/outheight);
const unsigned char* inrow2 = pIn + 4 * inwidth * (unsigned int)((i+0.75)*inheight/outheight);
//const unsigned char* inrow1 = pIn + inwidth * (unsigned int)((4*i+1)*inheight/outheight);
//const unsigned char* inrow2 = pIn + inwidth * (unsigned int)((4*i+3)*inheight/outheight);
// printf("inrow1: %d \t inrow2: %d \n",
// 4 * (unsigned int)((i+0.25)*inheight/outheight),
// 4 * (unsigned int)((i+0.75)*inheight/outheight)
// );
for (j=0; j<outwidth; j++)
{
const unsigned char* pix1 = inrow1 + p1[j];
const unsigned char* pix2 = inrow1 + p2[j];
const unsigned char* pix3 = inrow2 + p1[j];
const unsigned char* pix4 = inrow2 + p2[j];
unsigned char* pCurPix = pOut + j*4;
pCurPix[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
pCurPix[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
pCurPix[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
pCurPix[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
}
pOut += outwidth*4;
}
}
void GetScaledDimension(const unsigned int width, const unsigned int height, unsigned int * const outW, unsigned int * const outH, int isPicMip)
{
const unsigned int max_texture_size = 2048;
unsigned int scaled_width, scaled_height;
for(scaled_width = max_texture_size; scaled_width > width; scaled_width>>=1)
;
for (scaled_height = max_texture_size; scaled_height > height; scaled_height>>=1)
;
// perform optional picmip operation
if ( isPicMip )
{
scaled_width >>= r_picmip->integer;
scaled_height >>= r_picmip->integer;
}
// clamp to minimum size
if (scaled_width == 0) {
scaled_width = 1;
}
if (scaled_height == 0) {
scaled_height = 1;
}
*outW = scaled_width;
*outH = scaled_height;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// DEBUG HELPER FUNCTIONAS ...
///////////////////////////////////////////////////////////////////////////////////////////////
void imsave(char *fileName, unsigned char* buffer2, unsigned int width, unsigned int height);
void fsWriteFile( const char *qpath, const void *buffer, int size );
void fsWriteFile( const char *qpath, const void *buffer, int size )
{
unsigned char* buf = (unsigned char *)buffer;
FILE * f = fopen( qpath, "wb" );
if ( !f )
{
fprintf(stderr, "Failed to open %s\n", qpath );
return;
}
int remaining = size;
int tries = 0;
int block = 0;
int written = 0;
while (remaining)
{
block = remaining;
written = fwrite (buf, 1, block, f);
if (written == 0)
{
if (!tries)
{
tries = 1;
}
else
{
fprintf(stderr, "FS_Write: 0 bytes written\n" );
return;
}
}
if (written == -1)
{
fprintf(stderr, "FS_Write: -1 bytes written\n" );
return;
}
remaining -= written;
buf += written;
}
//FS_Write( buffer, size, f );
fclose(f);
}
void imsave(char *fileName, unsigned char* buffer2, unsigned int width, unsigned int height)
{
const unsigned int cnPixels = width * height;
unsigned char* buffer = (unsigned char*) malloc( cnPixels * 3 + 18);
memset (buffer, 0, 18);
buffer[2] = 2; // uncompressed type
buffer[12] = width & 255;
buffer[13] = width >> 8;
buffer[14] = height & 255;
buffer[15] = height >> 8;
buffer[16] = 24; // pixel size
unsigned char* buffer_ptr = buffer + 18;
unsigned char* buffer2_ptr = buffer2;
unsigned int i;
for (i = 0; i < cnPixels; i++)
{
buffer_ptr[0] = buffer2_ptr[0];
buffer_ptr[1] = buffer2_ptr[1];
buffer_ptr[2] = buffer2_ptr[2];
buffer_ptr += 3;
buffer2_ptr += 4;
}
// swap rgb to bgr
const unsigned int c = 18 + width * height * 3;
for (i=18; i<c; i+=3)
{
unsigned char temp = buffer[i];
buffer[i] = buffer[i+2];
buffer[i+2] = temp;
}
fsWriteFile( fileName, buffer, c );
free( buffer );
ri.Printf( PRINT_ALL, "imsave: %s\n", fileName );
}
void DEBUG_resample(const char *name, unsigned char* data, unsigned char* pBuffer,
unsigned int width, unsigned int height, unsigned int scaled_width, unsigned int scaled_height)
{
const char *slash = strrchr(name, '/');
char tmpName[128] = {0};
char tmpName2[128] = "resampled_";
strcpy(tmpName, slash+1);
strcat(tmpName2, tmpName);
imsave(tmpName , data, width, height);
imsave(tmpName2, pBuffer, scaled_width, scaled_height);
ri.Printf( PRINT_ALL, "tmpName: %s\n", tmpName);
ri.Printf( PRINT_ALL, "tmpName2: %s\n", tmpName2);
ri.Printf( PRINT_ALL, "DEBUG_resample, inwidth: %d, inheight: %d, outwidth: %d, outheight: %d\n",
width, height, scaled_width, scaled_height );
}

View file

@ -0,0 +1,15 @@
#ifndef R_IMAGE_PROCESS_H_
#define R_IMAHE_PROCESS_H_
void GetScaledDimension(const unsigned int width, const unsigned int height, unsigned int * const outW, unsigned int * const outH, int isPicMip);
void R_SetColorMappings( void );
void R_LightScaleTexture (unsigned char* dst, unsigned char* in, unsigned int nBytes);
void ResampleTexture(unsigned char *pOut, const unsigned int inwidth, const unsigned int inheight,
const unsigned char *pIn, const unsigned int outwidth, const unsigned int outheight);
void R_BlendOverTexture(unsigned char* data, const uint32_t pixelCount, const uint32_t l);
//void R_GammaCorrect(unsigned char* buffer, const unsigned int Size);
void R_MipMap(const unsigned char* in, uint32_t width, uint32_t height, unsigned char* out);
void R_MipMap2(const unsigned char* in, uint32_t inWidth, uint32_t inHeight, unsigned char* out);
#endif

View file

@ -0,0 +1,321 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "ref_import.h"
#include "image_loader.h"
/*
========================================================================
TGA files are used for 24/32 bit images
========================================================================
*/
typedef struct _TargaHeader {
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
} TargaHeader;
void R_LoadTGA ( const char *name, unsigned char** pic, int *width, int *height)
{
unsigned columns, rows, numPixels;
unsigned char *pixbuf;
int row, column;
unsigned char *buf_p;
unsigned char *end;
char * buffer;
TargaHeader targa_header;
unsigned char *targa_rgba;
int length;
*pic = NULL;
if(width)
*width = 0;
if(height)
*height = 0;
//
// load the file
//
length = ri.FS_ReadFile ( name, (void**)&buffer);
if (!buffer || length < 0) {
return;
}
if(length < 18)
{
ri.Error( ERR_DROP, "LoadTGA: header too short (%s)", name );
}
buf_p = (unsigned char*)buffer;
end = (unsigned char*)buffer + length;
targa_header.id_length = buf_p[0];
targa_header.colormap_type = buf_p[1];
targa_header.image_type = buf_p[2];
memcpy(&targa_header.colormap_index, &buf_p[3], 2);
memcpy(&targa_header.colormap_length, &buf_p[5], 2);
targa_header.colormap_size = buf_p[7];
memcpy(&targa_header.x_origin, &buf_p[8], 2);
memcpy(&targa_header.y_origin, &buf_p[10], 2);
memcpy(&targa_header.width, &buf_p[12], 2);
memcpy(&targa_header.height, &buf_p[14], 2);
targa_header.pixel_size = buf_p[16];
targa_header.attributes = buf_p[17];
targa_header.colormap_index = LittleShort(targa_header.colormap_index);
targa_header.colormap_length = LittleShort(targa_header.colormap_length);
targa_header.x_origin = LittleShort(targa_header.x_origin);
targa_header.y_origin = LittleShort(targa_header.y_origin);
targa_header.width = LittleShort(targa_header.width);
targa_header.height = LittleShort(targa_header.height);
buf_p += 18;
if (targa_header.image_type!=2
&& targa_header.image_type!=10
&& targa_header.image_type != 3 )
{
// leilei - made these far less fatal and more informative
ri.Printf( PRINT_WARNING, "LoadTGA: '%s' Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n", name);
//ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported");
return;
}
else if ( targa_header.colormap_type != 0 )
{
ri.Printf( PRINT_WARNING, "LoadTGA: '%s' colormaps not supported\n", name);
//ri.Error( ERR_DROP, "LoadTGA: colormaps not supported" );
return;
}
else if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
{
ri.Printf( PRINT_WARNING, "LoadTGA: '%s' Only 32 or 24 bit images supported (no colormaps)\n", name);
// ri.Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)");
return;
}
columns = targa_header.width;
rows = targa_header.height;
numPixels = columns * rows * 4;
if(!columns || !rows || numPixels > 0x7FFFFFFF || numPixels / columns / 4 != rows)
{
ri.Error (ERR_DROP, "LoadTGA: %s has an invalid image size", name);
}
targa_rgba = ri.Malloc (numPixels);
if (targa_header.id_length != 0)
{
if (buf_p + targa_header.id_length > end)
ri.Error( ERR_DROP, "LoadTGA: header too short (%s)", name );
buf_p += targa_header.id_length; // skip TARGA image comment
}
if ( targa_header.image_type==2 || targa_header.image_type == 3 )
{
if(buf_p + columns*rows*targa_header.pixel_size/8 > end)
{
ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name);
}
// Uncompressed RGB or gray scale image
for(row=rows-1; row>=0; row--)
{
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; column++)
{
unsigned char red,green,blue,alphabyte;
switch (targa_header.pixel_size)
{
case 8:
blue = *buf_p++;
green = blue;
red = blue;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
default:
ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'", targa_header.pixel_size, name );
break;
}
}
}
}
else if (targa_header.image_type==10) { // Runlength encoded RGB images
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
for(row=rows-1; row>=0; row--) {
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; ) {
if(buf_p + 1 > end)
ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name);
packetHeader= *buf_p++;
packetSize = 1 + (packetHeader & 0x7f);
if (packetHeader & 0x80) { // run-length packet
if(buf_p + targa_header.pixel_size/8 > end)
ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name);
switch (targa_header.pixel_size) {
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
break;
default:
ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'", targa_header.pixel_size, name );
break;
}
for(j=0;j<packetSize;j++) {
*pixbuf++=red;
*pixbuf++=green;
*pixbuf++=blue;
*pixbuf++=alphabyte;
column++;
if (column==columns) { // run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
else { // non run-length packet
if(buf_p + targa_header.pixel_size/8*packetSize > end)
ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name);
for(j=0;j<packetSize;j++) {
switch (targa_header.pixel_size) {
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
default:
ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'", targa_header.pixel_size, name );
break;
}
column++;
if (column==columns) { // pixel packet run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
}
breakOut:;
}
}
#if 0
// TTimo: this is the chunk of code to ensure a behavior that meets TGA specs
// bit 5 set => top-down
if (targa_header.attributes & 0x20) {
unsigned char *flip = (unsigned char*)malloc (columns*4);
unsigned char *src, *dst;
for (row = 0; row < rows/2; row++) {
src = targa_rgba + row * 4 * columns;
dst = targa_rgba + (rows - row - 1) * 4 * columns;
memcpy (flip, src, columns*4);
memcpy (src, dst, columns*4);
memcpy (dst, flip, columns*4);
}
free (flip);
}
#endif
// instead we just print a warning
if (targa_header.attributes & 0x20) {
ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name);
}
if (width)
*width = columns;
if (height)
*height = rows;
*pic = targa_rgba;
ri.FS_FreeFile (buffer);
}

177
code/renderervk/R_LerpTag.c Normal file
View file

@ -0,0 +1,177 @@
#include "tr_local.h"
#include "tr_model.h"
#include "ref_import.h"
static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) {
md3Tag_t *tag;
int i;
if ( frame >= mod->numFrames ) {
// it is possible to have a bad frame while changing models, so don't error
frame = mod->numFrames - 1;
}
tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags;
for ( i = 0 ; i < mod->numTags ; i++, tag++ ) {
if ( !strcmp( tag->name, tagName ) ) {
return tag; // found it
}
}
return NULL;
}
static md3Tag_t *R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest)
{
int i, j, k;
int frameSize;
mdrFrame_t *frame;
mdrTag_t *tag;
if ( framenum >= mod->numFrames )
{
// it is possible to have a bad frame while changing models, so don't error
framenum = mod->numFrames - 1;
}
tag = (mdrTag_t *)((byte *)mod + mod->ofsTags);
for ( i = 0 ; i < mod->numTags ; i++, tag++ )
{
if ( !strcmp( tag->name, tagName ) )
{
Q_strncpyz(dest->name, tag->name, sizeof(dest->name));
// uncompressed model...
//
frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] );
frame = (mdrFrame_t *)((byte *)mod + mod->ofsFrames + framenum * frameSize );
for (j = 0; j < 3; j++)
{
for (k = 0; k < 3; k++)
dest->axis[j][k]=frame->bones[tag->boneIndex].matrix[k][j];
}
dest->origin[0]=frame->bones[tag->boneIndex].matrix[0][3];
dest->origin[1]=frame->bones[tag->boneIndex].matrix[1][3];
dest->origin[2]=frame->bones[tag->boneIndex].matrix[2][3];
return dest;
}
}
return NULL;
}
static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) {
out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3];
out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7];
out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11];
}
static void ComputeJointMats( iqmData_t *data, int frame, int oldframe,
float backlerp, float *mat ) {
float *mat1;
int i;
ComputePoseMats( data, frame, oldframe, backlerp, mat );
for( i = 0; i < data->num_joints; i++ ) {
float outmat[12];
mat1 = mat + 12 * i;
memcpy(outmat, mat1, sizeof(outmat));
Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 );
}
}
static int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
int startFrame, int endFrame,
float frac, const char *tagName ) {
float jointMats[IQM_MAX_JOINTS * 12];
int joint;
char *names = data->names;
// get joint number by reading the joint names
for( joint = 0; joint < data->num_joints; joint++ ) {
if( !strcmp( tagName, names ) )
break;
names += strlen( names ) + 1;
}
if( joint >= data->num_joints ) {
memset(tag, 0, sizeof(orientation_t));
return qfalse;
}
ComputeJointMats( data, startFrame, endFrame, frac, jointMats );
tag->axis[0][0] = jointMats[12 * joint + 0];
tag->axis[1][0] = jointMats[12 * joint + 1];
tag->axis[2][0] = jointMats[12 * joint + 2];
tag->origin[0] = jointMats[12 * joint + 3];
tag->axis[0][1] = jointMats[12 * joint + 4];
tag->axis[1][1] = jointMats[12 * joint + 5];
tag->axis[2][1] = jointMats[12 * joint + 6];
tag->origin[1] = jointMats[12 * joint + 7];
tag->axis[0][2] = jointMats[12 * joint + 8];
tag->axis[1][2] = jointMats[12 * joint + 9];
tag->axis[2][2] = jointMats[12 * joint + 10];
tag->origin[2] = jointMats[12 * joint + 11];
return qtrue;
}
int RE_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
float frac, const char *tagName )
{
// ri.Printf(PRINT_ALL, "R_LerpTag\n");
md3Tag_t *start, *end;
md3Tag_t start_space, end_space;
model_t* model = R_GetModelByHandle( handle );
if ( !model->md3[0] )
{
if(model->type == MOD_MDR)
{
start = R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, &start_space);
end = R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, &end_space);
}
else if( model->type == MOD_IQM ) {
return R_IQMLerpTag( tag, model->modelData,
startFrame, endFrame,
frac, tagName );
} else {
start = end = NULL;
}
}
else
{
start = R_GetTag( model->md3[0], startFrame, tagName );
end = R_GetTag( model->md3[0], endFrame, tagName );
}
if ( !start || !end ) {
memset(tag, 0, sizeof(orientation_t));
return qfalse;
}
uint32_t i;
for ( i = 0 ; i < 3 ; i++ ) {
tag->origin[i] = start->origin[i] + (end->origin[i] - start->origin[i]) * frac;
tag->axis[0][i] = start->axis[0][i] + (end->axis[0][i] - start->axis[0][i]) * frac;
tag->axis[1][i] = start->axis[1][i] + (end->axis[1][i] - start->axis[1][i]) * frac;
tag->axis[2][i] = start->axis[2][i] + (end->axis[2][i] - start->axis[2][i]) * frac;
}
VectorNormalize( tag->axis[0] );
VectorNormalize( tag->axis[1] );
VectorNormalize( tag->axis[2] );
return qtrue;
}

View file

@ -0,0 +1,64 @@
#include "tr_globals.h"
#include "tr_shader.h"
#include "ref_import.h"
/*
===============
Dump information on all valid shaders to the console
A second parameter will cause it to print in sorted order
===============
*/
void R_ShaderList_f (void)
{
int i;
int count = 0;
shader_t* pShader;
ri.Printf (PRINT_ALL, "-----------------------\n");
for ( i = 0 ; i < tr.numShaders ; i++ )
{
if ( ri.Cmd_Argc() > 1 )
pShader = tr.sortedShaders[i];
else
pShader = tr.shaders[i];
ri.Printf( PRINT_ALL, "%i ", pShader->numUnfoggedPasses );
if (pShader->lightmapIndex >= 0 )
ri.Printf (PRINT_ALL, "L ");
else
ri.Printf (PRINT_ALL, " ");
if ( pShader->multitextureEnv == GL_ADD )
ri.Printf( PRINT_ALL, "MT(a) " );
else if ( pShader->multitextureEnv == GL_MODULATE )
ri.Printf( PRINT_ALL, "MT(m) " );
else
ri.Printf( PRINT_ALL, " " );
if ( pShader->explicitlyDefined )
ri.Printf( PRINT_ALL, "E " );
else
ri.Printf( PRINT_ALL, " " );
if ( !pShader->isSky )
ri.Printf( PRINT_ALL, "gen " );
else
ri.Printf( PRINT_ALL, "sky " );
if ( pShader->defaultShader )
ri.Printf (PRINT_ALL, ": %s (DEFAULTED)\n", pShader->name);
else
ri.Printf (PRINT_ALL, ": %s\n", pShader->name);
count++;
}
ri.Printf (PRINT_ALL, "%i total shaders\n", count);
ri.Printf (PRINT_ALL, "------------------\n");
}

View file

@ -0,0 +1,128 @@
#include "tr_local.h"
#include "ref_import.h"
#include "image_loader.h"
// Description: Loads any of the supported image types into
// a cannonical 32 bit format.
typedef struct
{
char *ext;
void (*ImageLoader)( const char *, unsigned char **, int *, int * );
} imageExtToLoaderMap_t;
// Note that the ordering indicates the order of preference used
// when there are multiple images of different formats available
const static imageExtToLoaderMap_t imageLoaders[6] =
{
{ "tga", R_LoadTGA },
{ "jpg", R_LoadJPG },
{ "jpeg", R_LoadJPG },
{ "png", R_LoadPNG },
{ "pcx", R_LoadPCX },
{ "bmp", R_LoadBMP }
};
const static int numImageLoaders = 6;
void R_LoadImage(const char *name, unsigned char **pic, int *width, int *height )
{
int orgLoader = -1;
int i;
char localName[ 128 ] = {0};
//int len = strlen(name);
const char* pSrc = name;
char* pDst = localName;
//char* dot = NULL;
char* pExt = NULL;
//char* slash = NULL;
*pic = NULL;
*width = 0;
*height = 0;
char c;
// copy name to localName
while( (c = *pDst++ = *pSrc++) )
{
if(c == '.')
pExt = pDst;
// else if(c == '/')
// slash = pDst-1;
}
if( pExt != NULL )
{
// Look for the correct loader and use it
for( i = 0; i < numImageLoaders; i++ )
{
if( !Q_stricmp( pExt, imageLoaders[ i ].ext ) )
{
orgLoader = i;
// Load
imageLoaders[ i ].ImageLoader( localName, pic, width, height );
if( *pic != NULL )
{
// Something loaded
return;
}
}
}
// Loader failed, most likely because the file isn't there;
// Try and find a suitable match using all the image formats supported
for( i = 0; i < numImageLoaders; i++ )
{
if (i == orgLoader)
continue;
strcpy(pExt, imageLoaders[ i ].ext);
// Load
imageLoaders[ i ].ImageLoader( localName, pic, width, height );
if( *pic != NULL )
{
// Something loaded
//ri.Printf( PRINT_WARNING, "%s not present, using %s instead\n", name, localName );
return;
}
}
ri.Printf( PRINT_WARNING, "%s not present\n", localName );
}
else
{
// Try and find a suitable match using all the image formats supported
*(pDst-1) = '.';
for( i = 0; i < numImageLoaders; i++ )
{
strcpy(pDst, imageLoaders[ i ].ext);
// Load
imageLoaders[ i ].ImageLoader( localName, pic, width, height );
if( *pic != NULL )
{
ri.Printf( PRINT_WARNING, "%s without a extension, using %s instead. \n",
name, localName);
return;
}
}
}
ri.Printf( PRINT_WARNING, "%s not present.\n", name);
// try again without the extension
}

View file

@ -0,0 +1,728 @@
#include "tr_local.h"
#include "ref_import.h"
static void* q3_stbi_malloc(size_t size) {
return ri.Malloc((int)size);
}
static void q3_stbi_free(void* p) {
ri.Free(p);
}
static void* q3_stbi_realloc(void* p, size_t old_size, size_t new_size) {
if (p == NULL)
return q3_stbi_malloc(new_size);
void* p_new;
if (old_size < new_size) {
p_new = q3_stbi_malloc(new_size);
memcpy(p_new, p, old_size);
q3_stbi_free(p);
} else {
p_new = p;
}
return p_new;
}
#define STBI_MALLOC q3_stbi_malloc
#define STBI_FREE q3_stbi_free
#define STBI_REALLOC_SIZED q3_stbi_realloc
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
static void LoadTGA( const char* name, unsigned char** pic, uint32_t* width, uint32_t* height);
static void LoadBMP( const char* name, unsigned char** pic, uint32_t* width, uint32_t* height);
static void LoadJPG( const char* name, unsigned char** pic, uint32_t* width, uint32_t* height);
static void LoadPCX32 ( const char* filename, unsigned char** pic, uint32_t* width, uint32_t* height);
/*
Loads any of the supported image types into a cannonical 32 bit format.
*/
void R_LoadImage2(const char *name, unsigned char **pic, uint32_t* width, uint32_t* height)
{
const int len = (int)strlen(name);
if (len<5)
{
ri.Printf( PRINT_WARNING, "R_LoadImage2: try to loading %s ? \n", name );
return;
}
// point to '.', .jped are assume not exist
const char* const pPnt = (char*)name + len - 4;
if(pPnt[0] == '.')
{ // have a extension
if( ( (pPnt[1] == 't') && (pPnt[2] == 'g') && (pPnt[3] == 'a') ) ||
( (pPnt[1] == 'T') && (pPnt[2] == 'G') && (pPnt[3] == 'A') ) )
{
LoadTGA( name, pic, width, height );
if (NULL == *pic)
{
// try jpg in place of tga
char altname[128] = {0};
strncpy( altname, name, 128 );
char* pt = altname + len - 4;
pt[1] = 'j';
pt[2] = 'p';
pt[3] = 'g';
LoadJPG( altname, pic, width, height );
}
}
else if ( ( (pPnt[1] == 'j') && (pPnt[2] == 'p') && (pPnt[3] == 'g') ) ||
( (pPnt[1] == 'J') && (pPnt[2] == 'P') && (pPnt[3] == 'G') ) )
{
LoadJPG( name, pic, width, height );
}
else if ( ( (pPnt[1] == 'b') && (pPnt[2] == 'm') && (pPnt[3] == 'p') ) ||
( (pPnt[1] == 'B') && (pPnt[2] == 'M') && (pPnt[3] == 'P') ) )
{
LoadBMP( name, pic, width, height );
}
else if ( ( (pPnt[1] == 'p') && (pPnt[2] == 'c') && (pPnt[3] == 'x') ) ||
( (pPnt[1] == 'P') && (pPnt[2] == 'C') && (pPnt[3] == 'X') ) )
{
LoadPCX32( name, pic, width, height );
}
}
else
{ // without a extension
// Try and find a suitable match using all the image formats supported
char altname[128] = {0};
strcpy( altname, name );
char* pt = altname + len;
pt[0] = '.';
pt[1] = 't';
pt[2] = 'g';
pt[3] = 'a';
pt[4] = '\0';
LoadTGA( altname, pic, width, height );
if (NULL == *pic)
{
// try jpg in place of tga
pt[0] = '.';
pt[1] = 'j';
pt[2] = 'p';
pt[3] = 'g';
pt[4] = '\0';
LoadJPG( altname, pic, width, height );
}
if( *pic == NULL )
{
ri.Printf( PRINT_WARNING, "%s not present.\n", name);
}
// else
// ri.Printf( PRINT_ALL, "%s without a extension, using %s instead. \n", name, altname);
}
}
// ====================================== //
// ====================================== //
typedef struct _TargaHeader {
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
} TargaHeader;
static void LoadTGA( const char* name, unsigned char** pic, uint32_t* width, uint32_t* height)
{
int columns, rows, numPixels;
unsigned char* pixbuf;
int row, column;
char* buffer;
TargaHeader targa_header;
*pic = NULL;
//
// load the file
//
ri.FS_ReadFile(name, (void**)&buffer);
if (!buffer) {
return;
}
char* buf_p = buffer;
targa_header.id_length = *buf_p++;
targa_header.colormap_type = *buf_p++;
targa_header.image_type = *buf_p++;
targa_header.colormap_index = LittleShort ( *(short *)buf_p );
buf_p += 2;
targa_header.colormap_length = LittleShort ( *(short *)buf_p );
buf_p += 2;
targa_header.colormap_size = *buf_p++;
targa_header.x_origin = LittleShort ( *(short *)buf_p );
buf_p += 2;
targa_header.y_origin = LittleShort ( *(short *)buf_p );
buf_p += 2;
targa_header.width = LittleShort ( *(short *)buf_p );
buf_p += 2;
targa_header.height = LittleShort ( *(short *)buf_p );
buf_p += 2;
targa_header.pixel_size = *buf_p++;
targa_header.attributes = *buf_p++;
if (targa_header.image_type!=2
&& targa_header.image_type!=10
&& targa_header.image_type != 3 )
{
ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
}
if ( targa_header.colormap_type != 0 )
{
ri.Error( ERR_DROP, "LoadTGA: colormaps not supported\n" );
}
if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 )
{
ri.Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
}
columns = targa_header.width;
rows = targa_header.height;
numPixels = columns * rows;
if (width)
*width = columns;
if (height)
*height = rows;
unsigned char* targa_rgba = (unsigned char*) ri.Malloc (numPixels*4);
*pic = targa_rgba;
if (targa_header.id_length != 0)
buf_p += targa_header.id_length; // skip TARGA image comment
if ( targa_header.image_type==2 || targa_header.image_type == 3 )
{
// Uncompressed RGB or gray scale image
for(row=rows-1; row>=0; row--)
{
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; column++)
{
unsigned char red,green,blue,alphabyte;
switch (targa_header.pixel_size)
{
case 8:
blue = *buf_p++;
green = blue;
red = blue;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
default:
ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
break;
}
}
}
}
else if (targa_header.image_type==10) { // Runlength encoded RGB images
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
red = 0;
green = 0;
blue = 0;
alphabyte = 0xff;
for(row=rows-1; row>=0; row--) {
pixbuf = targa_rgba + row*columns*4;
for(column=0; column<columns; ) {
packetHeader= *buf_p++;
packetSize = 1 + (packetHeader & 0x7f);
if (packetHeader & 0x80) { // run-length packet
switch (targa_header.pixel_size) {
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
break;
default:
ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
break;
}
for(j=0;j<packetSize;j++) {
*pixbuf++=red;
*pixbuf++=green;
*pixbuf++=blue;
*pixbuf++=alphabyte;
column++;
if (column==columns) { // run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
else { // non run-length packet
for(j=0;j<packetSize;j++) {
switch (targa_header.pixel_size) {
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alphabyte = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alphabyte;
break;
default:
ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
break;
}
column++;
if (column==columns) { // pixel packet run spans across rows
column=0;
if (row>0)
row--;
else
goto breakOut;
pixbuf = targa_rgba + row*columns*4;
}
}
}
}
breakOut:;
}
}
#if 0
// TTimo: this is the chunk of code to ensure a behavior that meets TGA specs
// bk0101024 - fix from Leonardo
// bit 5 set => top-down
if (targa_header.attributes & 0x20) {
unsigned char *flip = (unsigned char*)malloc (columns*4);
unsigned char *src, *dst;
for (row = 0; row < rows/2; row++) {
src = targa_rgba + row * 4 * columns;
dst = targa_rgba + (rows - row - 1) * 4 * columns;
memcpy (flip, src, columns*4);
memcpy (src, dst, columns*4);
memcpy (dst, flip, columns*4);
}
free (flip);
}
#endif
// instead we just print a warning
if (targa_header.attributes & 0x20) {
ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name);
}
ri.FS_FreeFile (buffer);
}
static void LoadJPG( const char* name, unsigned char** pic, uint32_t* width, uint32_t* height)
{
char* fbuffer;
int len = ri.FS_ReadFile(name, (void**)&fbuffer);
if (!fbuffer) {
return;
}
int components;
*pic = stbi_load_from_memory((unsigned char*)fbuffer, len, (int*)width, (int*)height, &components, STBI_rgb_alpha);
if (*pic == NULL) {
ri.FS_FreeFile(fbuffer);
return;
}
// clear all the alphas to 255
{
unsigned int i;
unsigned char* buf = *pic;
unsigned int nBytes = 4 * (*width) * (*height);
for (i = 3; i < nBytes; i += 4)
{
buf[i] = 255;
}
}
ri.FS_FreeFile(fbuffer);
}
/*
=========================================================
BMP LOADING
=========================================================
*/
typedef struct
{
char id[2];
unsigned long fileSize;
unsigned long reserved0;
unsigned long bitmapDataOffset;
unsigned long bitmapHeaderSize;
unsigned long width;
unsigned long height;
unsigned short planes;
unsigned short bitsPerPixel;
unsigned long compression;
unsigned long bitmapDataSize;
unsigned long hRes;
unsigned long vRes;
unsigned long colors;
unsigned long importantColors;
unsigned char palette[256][4];
} BMPHeader_t;
static void LoadBMP( const char *name, unsigned char **pic, uint32_t *width, uint32_t *height )
{
int columns, rows, numPixels;
unsigned char *pixbuf;
int row, column;
char* buf_p;
char* buffer;
int length;
BMPHeader_t bmpHeader;
unsigned char *bmpRGBA;
*pic = NULL;
//
// load the file
//
length = ri.FS_ReadFile(name, (void**)&buffer);
if (!buffer) {
return;
}
buf_p = buffer;
bmpHeader.id[0] = *buf_p++;
bmpHeader.id[1] = *buf_p++;
bmpHeader.fileSize = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.reserved0 = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.bitmapDataOffset = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.bitmapHeaderSize = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.width = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.height = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.planes = LittleShort( * ( short * ) buf_p );
buf_p += 2;
bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p );
buf_p += 2;
bmpHeader.compression = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.bitmapDataSize = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.hRes = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.vRes = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.colors = LittleLong( * ( long * ) buf_p );
buf_p += 4;
bmpHeader.importantColors = LittleLong( * ( long * ) buf_p );
buf_p += 4;
memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) );
if ( bmpHeader.bitsPerPixel == 8 )
buf_p += 1024;
if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' )
{
ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name );
}
if ( bmpHeader.fileSize != length )
{
ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%ld vs. %d) (%s)\n", bmpHeader.fileSize, length, name );
}
if ( bmpHeader.compression != 0 )
{
ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name );
}
if ( bmpHeader.bitsPerPixel < 8 )
{
ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name );
}
columns = bmpHeader.width;
rows = bmpHeader.height;
if ( rows < 0 )
rows = -rows;
numPixels = columns * rows;
if ( width )
*width = columns;
if ( height )
*height = rows;
bmpRGBA = (unsigned char*) ri.Malloc( numPixels * 4 );
*pic = bmpRGBA;
for ( row = rows-1; row >= 0; row-- )
{
pixbuf = bmpRGBA + row*columns*4;
for ( column = 0; column < columns; column++ )
{
unsigned char red, green, blue, alpha;
int palIndex;
unsigned short shortPixel;
switch ( bmpHeader.bitsPerPixel )
{
case 8:
palIndex = *buf_p++;
*pixbuf++ = bmpHeader.palette[palIndex][2];
*pixbuf++ = bmpHeader.palette[palIndex][1];
*pixbuf++ = bmpHeader.palette[palIndex][0];
*pixbuf++ = 0xff;
break;
case 16:
shortPixel = * ( unsigned short * ) pixbuf;
pixbuf += 2;
*pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7;
*pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2;
*pixbuf++ = ( shortPixel & ( 31 ) ) << 3;
*pixbuf++ = 0xff;
break;
case 24:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = 255;
break;
case 32:
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alpha = *buf_p++;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alpha;
break;
default:
ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name );
break;
}
}
}
ri.FS_FreeFile( buffer );
}
typedef struct {
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
char data; // unbounded
} pcx_t;
static void LoadPCX ( const char *filename, unsigned char **pic, unsigned char **palette, uint32_t *width, uint32_t *height)
{
char* raw;
pcx_t *pcx;
int x, y;
int len;
int dataByte, runLength;
unsigned char *out, *pix;
int xmax, ymax;
*pic = NULL;
*palette = NULL;
//
// load the file
//
len = ri.FS_ReadFile(filename, (void**)&raw);
if (!raw) {
return;
}
//
// parse the PCX file
//
pcx = (pcx_t *)raw;
raw = &pcx->data;
xmax = LittleShort(pcx->xmax);
ymax = LittleShort(pcx->ymax);
if (pcx->manufacturer != 0x0a
|| pcx->version != 5
|| pcx->encoding != 1
|| pcx->bits_per_pixel != 8
|| xmax >= 1024
|| ymax >= 1024)
{
ri.Printf (PRINT_ALL, "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax);
return;
}
out = (unsigned char*) ri.Malloc ( (ymax+1) * (xmax+1) );
*pic = out;
pix = out;
if (palette)
{
*palette = (unsigned char*) ri.Malloc(768);
memcpy (*palette, (unsigned char *)pcx + len - 768, 768);
}
if (width)
*width = xmax+1;
if (height)
*height = ymax+1;
// FIXME: use bytes_per_line here?
for (y=0 ; y<=ymax ; y++, pix += xmax+1)
{
for (x=0 ; x<=xmax ; )
{
dataByte = *raw++;
if((dataByte & 0xC0) == 0xC0)
{
runLength = dataByte & 0x3F;
dataByte = *raw++;
}
else
runLength = 1;
while(runLength-- > 0)
pix[x++] = dataByte;
}
}
if ( raw - (char *)pcx > len)
{
ri.Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename);
ri.Free (*pic);
*pic = NULL;
}
ri.FS_FreeFile (pcx);
}
static void LoadPCX32 ( const char *filename, unsigned char **pic, uint32_t *width, uint32_t *height)
{
unsigned char *palette;
unsigned char *pic8;
int i, c, p;
unsigned char *pic32;
LoadPCX (filename, &pic8, &palette, width, height);
if (!pic8) {
*pic = NULL;
return;
}
c = (*width) * (*height);
pic32 = *pic = (unsigned char*) ri.Malloc(4 * c );
for (i = 0 ; i < c ; i++) {
p = pic8[i];
pic32[0] = palette[p*3];
pic32[1] = palette[p*3 + 1];
pic32[2] = palette[p*3 + 2];
pic32[3] = 255;
pic32 += 4;
}
ri.Free (pic8);
ri.Free (palette);
}

270
code/renderervk/R_LoadMD3.c Normal file
View file

@ -0,0 +1,270 @@
#include "tr_local.h"
#include "tr_model.h"
#include "ref_import.h"
#include "tr_shader.h"
#define LL(x) x=LittleLong(x)
static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name )
{
int i, j;
md3Header_t *pinmodel;
md3Frame_t *frame;
md3Surface_t *surf;
md3Shader_t *shader;
md3Triangle_t *tri;
md3St_t *st;
md3XyzNormal_t *xyz;
md3Tag_t *tag;
int version;
int size;
pinmodel = (md3Header_t *)buffer;
version = LittleLong (pinmodel->version);
if (version != MD3_VERSION) {
ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
mod_name, version, MD3_VERSION);
return qfalse;
}
mod->type = MOD_MESH;
size = LittleLong(pinmodel->ofsEnd);
mod->dataSize += size;
mod->md3[lod] = ri.Hunk_Alloc( size, h_low );
memcpy (mod->md3[lod], buffer, LittleLong(pinmodel->ofsEnd) );
LL(mod->md3[lod]->ident);
LL(mod->md3[lod]->version);
LL(mod->md3[lod]->numFrames);
LL(mod->md3[lod]->numTags);
LL(mod->md3[lod]->numSurfaces);
LL(mod->md3[lod]->ofsFrames);
LL(mod->md3[lod]->ofsTags);
LL(mod->md3[lod]->ofsSurfaces);
LL(mod->md3[lod]->ofsEnd);
if ( mod->md3[lod]->numFrames < 1 ) {
ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
return qfalse;
}
// swap all the frames
frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
frame->radius = LittleFloat( frame->radius );
for ( j = 0 ; j < 3 ; j++ ) {
frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
}
}
// swap all the tags
tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
for ( j = 0 ; j < 3 ; j++ ) {
tag->origin[j] = LittleFloat( tag->origin[j] );
tag->axis[0][j] = LittleFloat( tag->axis[0][j] );
tag->axis[1][j] = LittleFloat( tag->axis[1][j] );
tag->axis[2][j] = LittleFloat( tag->axis[2][j] );
}
}
// swap all the surfaces
surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
LL(surf->ident);
LL(surf->flags);
LL(surf->numFrames);
LL(surf->numShaders);
LL(surf->numTriangles);
LL(surf->ofsTriangles);
LL(surf->numVerts);
LL(surf->ofsShaders);
LL(surf->ofsSt);
LL(surf->ofsXyzNormals);
LL(surf->ofsEnd);
if ( surf->numVerts >= SHADER_MAX_VERTEXES ) {
ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n",
mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface",
surf->numVerts );
return qfalse;
}
if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) {
ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n",
mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface",
surf->numTriangles );
return qfalse;
}
// change to surface identifier
surf->ident = SF_MD3;
// lowercase the surface name so skin compares are faster
Q_strlwr( surf->name );
// strip off a trailing _1 or _2
// this is a crutch for q3data being a mess
j = strlen( surf->name );
if ( j > 2 && surf->name[j-2] == '_' ) {
surf->name[j-2] = 0;
}
// register the shaders
shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
shader_t* sh = R_FindShader( shader->name, LIGHTMAP_NONE, qtrue );
if ( sh->defaultShader ) {
shader->shaderIndex = 0;
} else {
shader->shaderIndex = sh->index;
}
}
// swap all the triangles
tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
LL(tri->indexes[0]);
LL(tri->indexes[1]);
LL(tri->indexes[2]);
}
// swap all the ST
st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
st->st[0] = LittleFloat( st->st[0] );
st->st[1] = LittleFloat( st->st[1] );
}
// swap all the XyzNormals
xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
{
xyz->xyz[0] = LittleShort( xyz->xyz[0] );
xyz->xyz[1] = LittleShort( xyz->xyz[1] );
xyz->xyz[2] = LittleShort( xyz->xyz[2] );
xyz->normal = LittleShort( xyz->normal );
}
// find the next surface
surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
}
return qtrue;
}
qhandle_t R_RegisterMD3(const char* name, model_t* mod)
{
char* buf;
int numLoaded = 0;
ri.FS_ReadFile( name, (void**)&buf );
if( NULL != buf)
{
qboolean loaded = qfalse;
#if defined( Q3_BIG_ENDIAN )
int ident = LittleLong(*(int *)buf);
#else
int ident = *(int *)buf;
#endif
if (ident == MD3_IDENT)
loaded = R_LoadMD3(mod, 0, buf, name);
else
ri.Printf(PRINT_WARNING,"R_RegisterMD3: unknown fileid for %s\n", name);
ri.FS_FreeFile(buf);
if(loaded)
{
mod->numLods++;
numLoaded++;
}
else
{
ri.Printf(PRINT_WARNING, "R_RegisterMD3: couldn't load %s\n", name);
mod->type = MOD_BAD;
return 0;
}
}
else
{
ri.Printf(PRINT_WARNING, "R_RegisterMD3: failed loading %s from disk. \n", name);
}
char filename[MAX_QPATH] = {0};
strcpy(filename, name);
char* const dot = strrchr(filename, '.');
*dot = 0;
uint32_t lod;
for (lod = 1; lod < MD3_MAX_LODS; lod++)
{
qboolean loaded = qfalse;
char namebuf[MAX_QPATH+20] = {0};
snprintf(namebuf, sizeof(namebuf), "%s_%d.md3", filename, lod);
ri.FS_ReadFile( namebuf, (void**)&buf );
if(!buf)
continue;
#if defined( Q3_BIG_ENDIAN )
int ident = LittleLong(*(int *)buf);
#else
int ident = *(int *)buf;
#endif
if (ident == MD3_IDENT)
loaded = R_LoadMD3(mod, lod, buf, name);
else
ri.Printf(PRINT_WARNING, "R_RegisterMD3: unknown fileid for %s\n", name);
ri.FS_FreeFile(buf);
if(loaded)
{
mod->numLods++;
numLoaded++;
}
else
break;
}
if(numLoaded)
return mod->index;
else
ri.Printf(PRINT_WARNING, "R_RegisterMD3: couldn't load %s\n", name);
/*
if(numLoaded)
{
// duplicate into higher lod spots that weren't loaded,
// in case the user changes r_lodbias on the fly
for(lod--; lod >= 0; lod--)
{
mod->numLods++;
mod->md3[lod] = mod->md3[lod + 1];
}
return mod->index;
}
*/
mod->type = MOD_BAD;
return 0;
}

527
code/renderervk/R_LoadMDR.c Normal file
View file

@ -0,0 +1,527 @@
#include "tr_local.h"
#include "tr_model.h"
#include "ref_import.h"
#include "tr_shader.h"
#define LL(x) x=LittleLong(x)
/*
=============================================================
UNCOMPRESSING BONES
=============================================================
*/
#define MC_BITS_X (16)
#define MC_BITS_Y (16)
#define MC_BITS_Z (16)
#define MC_BITS_VECT (16)
#define MC_SCALE_X (1.0f/64)
#define MC_SCALE_Y (1.0f/64)
#define MC_SCALE_Z (1.0f/64)
#define MC_MASK_X ((1<<(MC_BITS_X))-1)
#define MC_MASK_Y ((1<<(MC_BITS_Y))-1)
#define MC_MASK_Z ((1<<(MC_BITS_Z))-1)
#define MC_MASK_VECT ((1<<(MC_BITS_VECT))-1)
#define MC_SCALE_VECT (1.0f/(float)((1<<(MC_BITS_VECT-1))-2))
#define MC_POS_X (0)
#define MC_SHIFT_X (0)
#define MC_POS_Y ((((MC_BITS_X))/8))
#define MC_SHIFT_Y ((((MC_BITS_X)%8)))
#define MC_POS_Z ((((MC_BITS_X+MC_BITS_Y))/8))
#define MC_SHIFT_Z ((((MC_BITS_X+MC_BITS_Y)%8)))
#define MC_POS_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z))/8))
#define MC_SHIFT_V11 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z)%8)))
#define MC_POS_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT))/8))
#define MC_SHIFT_V12 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT)%8)))
#define MC_POS_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2))/8))
#define MC_SHIFT_V13 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*2)%8)))
#define MC_POS_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3))/8))
#define MC_SHIFT_V21 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*3)%8)))
#define MC_POS_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4))/8))
#define MC_SHIFT_V22 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*4)%8)))
#define MC_POS_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5))/8))
#define MC_SHIFT_V23 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*5)%8)))
#define MC_POS_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6))/8))
#define MC_SHIFT_V31 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*6)%8)))
#define MC_POS_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7))/8))
#define MC_SHIFT_V32 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*7)%8)))
#define MC_POS_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8))/8))
#define MC_SHIFT_V33 ((((MC_BITS_X+MC_BITS_Y+MC_BITS_Z+MC_BITS_VECT*8)%8)))
void MC_UnCompress(float mat[3][4], const unsigned char* comp)
{
int val;
val=(int)((unsigned short *)(comp))[0];
val-=1<<(MC_BITS_X-1);
mat[0][3]=((float)(val))*MC_SCALE_X;
val=(int)((unsigned short *)(comp))[1];
val-=1<<(MC_BITS_Y-1);
mat[1][3]=((float)(val))*MC_SCALE_Y;
val=(int)((unsigned short *)(comp))[2];
val-=1<<(MC_BITS_Z-1);
mat[2][3]=((float)(val))*MC_SCALE_Z;
val=(int)((unsigned short *)(comp))[3];
val-=1<<(MC_BITS_VECT-1);
mat[0][0]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[4];
val-=1<<(MC_BITS_VECT-1);
mat[0][1]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[5];
val-=1<<(MC_BITS_VECT-1);
mat[0][2]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[6];
val-=1<<(MC_BITS_VECT-1);
mat[1][0]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[7];
val-=1<<(MC_BITS_VECT-1);
mat[1][1]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[8];
val-=1<<(MC_BITS_VECT-1);
mat[1][2]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[9];
val-=1<<(MC_BITS_VECT-1);
mat[2][0]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[10];
val-=1<<(MC_BITS_VECT-1);
mat[2][1]=((float)(val))*MC_SCALE_VECT;
val=(int)((unsigned short *)(comp))[11];
val-=1<<(MC_BITS_VECT-1);
mat[2][2]=((float)(val))*MC_SCALE_VECT;
}
qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name )
{
int i, j, k, l;
mdrHeader_t *pinmodel, *mdr;
mdrFrame_t *frame;
mdrLOD_t *lod, *curlod;
mdrSurface_t *surf, *cursurf;
mdrTriangle_t *tri, *curtri;
mdrVertex_t *v, *curv;
mdrWeight_t *weight, *curweight;
mdrTag_t *tag, *curtag;
int size;
shader_t *sh;
pinmodel = (mdrHeader_t *)buffer;
pinmodel->version = LittleLong(pinmodel->version);
if (pinmodel->version != MDR_VERSION)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has wrong version (%i should be %i)\n", mod_name, pinmodel->version, MDR_VERSION);
return qfalse;
}
size = LittleLong(pinmodel->ofsEnd);
if(size > filesize)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: Header of %s is broken. Wrong filesize declared!\n", mod_name);
return qfalse;
}
mod->type = MOD_MDR;
LL(pinmodel->numFrames);
LL(pinmodel->numBones);
LL(pinmodel->ofsFrames);
// This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
// over and over again, we'll uncompress it in this function already, so we must adjust the size of the target mdr.
if(pinmodel->ofsFrames < 0)
{
// mdrFrame_t is larger than mdrCompFrame_t:
size += pinmodel->numFrames * sizeof(frame->name);
// now add enough space for the uncompressed bones.
size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
}
// simple bounds check
if(pinmodel->numBones < 0 ||
sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
mod->dataSize += size;
mod->modelData = mdr = ri.Hunk_Alloc( size, h_low );
// Copy all the values over from the file and fix endian issues in the process, if necessary.
mdr->ident = LittleLong(pinmodel->ident);
mdr->version = pinmodel->version; // Don't need to swap byte order on this one, we already did above.
Q_strncpyz(mdr->name, pinmodel->name, sizeof(mdr->name));
mdr->numFrames = pinmodel->numFrames;
mdr->numBones = pinmodel->numBones;
mdr->numLODs = LittleLong(pinmodel->numLODs);
mdr->numTags = LittleLong(pinmodel->numTags);
// We don't care about the other offset values, we'll generate them ourselves while loading.
mod->numLods = mdr->numLODs;
if ( mdr->numFrames < 1 )
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has no frames\n", mod_name);
return qfalse;
}
/* The first frame will be put into the first free space after the header */
frame = (mdrFrame_t *)(mdr + 1);
mdr->ofsFrames = (int)((byte *) frame - (byte *) mdr);
if (pinmodel->ofsFrames < 0)
{
mdrCompFrame_t *cframe;
// compressed model...
cframe = (mdrCompFrame_t *)((byte *) pinmodel - pinmodel->ofsFrames);
for(i = 0; i < mdr->numFrames; i++)
{
for(j = 0; j < 3; j++)
{
frame->bounds[0][j] = LittleFloat(cframe->bounds[0][j]);
frame->bounds[1][j] = LittleFloat(cframe->bounds[1][j]);
frame->localOrigin[j] = LittleFloat(cframe->localOrigin[j]);
}
frame->radius = LittleFloat(cframe->radius);
frame->name[0] = '\0'; // No name supplied in the compressed version.
for(j = 0; j < mdr->numBones; j++)
{
#if defined( Q3_BIG_ENDIAN )
for(k = 0; k < (sizeof(cframe->bones[j].Comp) / 2); k++)
{
// Do swapping for the uncompressing functions. They seem to use shorts
// values only, so I assume this will work. Never tested it on other
// platforms, though.
((unsigned short *)(cframe->bones[j].Comp))[k] =
LittleShort( ((unsigned short *)(cframe->bones[j].Comp))[k] );
}
#endif
/* Now do the actual uncompressing */
MC_UnCompress(frame->bones[j].matrix, cframe->bones[j].Comp);
}
// Next Frame...
// cframe = (mdrCompFrame_t *) &cframe->bones[j];
// frame = (mdrFrame_t *) &frame->bones[j];
// this suppress GCC strict-aliasing warning
{
// Next Frame...
mdrCompBone_t *p = &(cframe->bones[j]);
cframe = (mdrCompFrame_t *) p;
}
{
mdrBone_t *p = &frame->bones[j];
frame = (mdrFrame_t *) p;
}
}
}
else
{
mdrFrame_t *curframe;
// uncompressed model...
//
curframe = (mdrFrame_t *)((byte *) pinmodel + pinmodel->ofsFrames);
// swap all the frames
for ( i = 0 ; i < mdr->numFrames ; i++)
{
for(j = 0; j < 3; j++)
{
frame->bounds[0][j] = LittleFloat(curframe->bounds[0][j]);
frame->bounds[1][j] = LittleFloat(curframe->bounds[1][j]);
frame->localOrigin[j] = LittleFloat(curframe->localOrigin[j]);
}
frame->radius = LittleFloat(curframe->radius);
Q_strncpyz(frame->name, curframe->name, sizeof(frame->name));
// suppress GCC strict-aliasing warning
#if defined( Q3_BIG_ENDIAN )
for (j = 0; j < (int) (mdr->numBones * sizeof(mdrBone_t) / 4); j++)
{
((float *)frame->bones)[j]=FloatSwap(&((float *)curframe->bones)[j]);
}
#else
for (j = 0; j < mdr->numBones; j++)
{
frame->bones[j] = curframe->bones[j];
}
#endif
//curframe = (mdrFrame_t *) &curframe->bones[mdr->numBones];
//frame = (mdrFrame_t *) &frame->bones[mdr->numBones];
// suppress GCC strict-aliasing warning
{
mdrBone_t* p = &curframe->bones[mdr->numBones];
curframe = (mdrFrame_t *) p;
}
{
mdrBone_t* p = &frame->bones[mdr->numBones];
frame = (mdrFrame_t *) p;
}
}
}
// frame should now point to the first free address after all frames.
lod = (mdrLOD_t *) frame;
mdr->ofsLODs = (int) ((byte *) lod - (byte *)mdr);
curlod = (mdrLOD_t *)((byte *) pinmodel + LittleLong(pinmodel->ofsLODs));
// swap all the LOD's
for ( l = 0 ; l < mdr->numLODs ; l++)
{
// simple bounds check
if((byte *) (lod + 1) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
lod->numSurfaces = LittleLong(curlod->numSurfaces);
// swap all the surfaces
surf = (mdrSurface_t *) (lod + 1);
lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
for ( i = 0 ; i < lod->numSurfaces ; i++)
{
// simple bounds check
if((byte *) (surf + 1) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
// first do some copying stuff
surf->ident = SF_MDR;
Q_strncpyz(surf->name, cursurf->name, sizeof(surf->name));
Q_strncpyz(surf->shader, cursurf->shader, sizeof(surf->shader));
surf->ofsHeader = (byte *) mdr - (byte *) surf;
surf->numVerts = LittleLong(cursurf->numVerts);
surf->numTriangles = LittleLong(cursurf->numTriangles);
// numBoneReferences and BoneReferences generally seem to be unused
// now do the checks that may fail.
if ( surf->numVerts >= SHADER_MAX_VERTEXES )
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n",
mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface",
surf->numVerts );
return qfalse;
}
if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES )
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n",
mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface",
surf->numTriangles );
return qfalse;
}
// lowercase the surface name so skin compares are faster
Q_strlwr( surf->name );
// register the shaders
sh = R_FindShader(surf->shader, LIGHTMAP_NONE, qtrue);
if ( sh->defaultShader ) {
surf->shaderIndex = 0;
} else {
surf->shaderIndex = sh->index;
}
// now copy the vertexes.
v = (mdrVertex_t *) (surf + 1);
surf->ofsVerts = (int)((byte *) v - (byte *) surf);
curv = (mdrVertex_t *) ((byte *)cursurf + LittleLong(cursurf->ofsVerts));
for(j = 0; j < surf->numVerts; j++)
{
LL(curv->numWeights);
// simple bounds check
if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
v->normal[0] = LittleFloat(curv->normal[0]);
v->normal[1] = LittleFloat(curv->normal[1]);
v->normal[2] = LittleFloat(curv->normal[2]);
v->texCoords[0] = LittleFloat(curv->texCoords[0]);
v->texCoords[1] = LittleFloat(curv->texCoords[1]);
v->numWeights = curv->numWeights;
weight = &v->weights[0];
curweight = &curv->weights[0];
// Now copy all the weights
for(k = 0; k < v->numWeights; k++)
{
weight->boneIndex = LittleLong(curweight->boneIndex);
weight->boneWeight = LittleFloat(curweight->boneWeight);
weight->offset[0] = LittleFloat(curweight->offset[0]);
weight->offset[1] = LittleFloat(curweight->offset[1]);
weight->offset[2] = LittleFloat(curweight->offset[2]);
weight++;
curweight++;
}
v = (mdrVertex_t *) weight;
curv = (mdrVertex_t *) curweight;
}
// we know the offset to the triangles now:
tri = (mdrTriangle_t *) v;
surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
// simple bounds check
if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
for(j = 0; j < surf->numTriangles; j++)
{
tri->indexes[0] = LittleLong(curtri->indexes[0]);
tri->indexes[1] = LittleLong(curtri->indexes[1]);
tri->indexes[2] = LittleLong(curtri->indexes[2]);
tri++;
curtri++;
}
// tri now points to the end of the surface.
surf->ofsEnd = (byte *) tri - (byte *) surf;
surf = (mdrSurface_t *) tri;
// find the next surface.
cursurf = (mdrSurface_t *) ((byte *) cursurf + LittleLong(cursurf->ofsEnd));
}
// surf points to the next lod now.
lod->ofsEnd = (int)((byte *) surf - (byte *) lod);
lod = (mdrLOD_t *) surf;
// find the next LOD.
curlod = (mdrLOD_t *)((byte *) curlod + LittleLong(curlod->ofsEnd));
}
// lod points to the first tag now, so update the offset too.
tag = (mdrTag_t *) lod;
mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
// simple bounds check
if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
for (i = 0 ; i < mdr->numTags ; i++)
{
tag->boneIndex = LittleLong(curtag->boneIndex);
Q_strncpyz(tag->name, curtag->name, sizeof(tag->name));
tag++;
curtag++;
}
// And finally we know the real offset to the end.
mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);
// phew! we're done.
return qtrue;
}
qhandle_t R_RegisterMDR(const char *name, model_t *mod)
{
char* buf;
qboolean loaded = qfalse;
int filesize = ri.FS_ReadFile(name, (void**)&buf);
if(!buf)
{
mod->type = MOD_BAD;
return 0;
}
#if defined( Q3_BIG_ENDIAN )
int ident = LittleLong(*(int *)buf);
#else
int ident = *(int *)buf;
#endif
if(ident == MDR_IDENT)
loaded = R_LoadMDR(mod, buf, filesize, name);
ri.FS_FreeFile(buf);
if(!loaded)
{
ri.Printf(PRINT_WARNING,"R_RegisterMDR: couldn't load mdr file %s\n", name);
mod->type = MOD_BAD;
return 0;
}
return mod->index;
}

View file

@ -0,0 +1,48 @@
#include "tr_local.h"
#include "tr_model.h"
void RE_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs )
{
model_t* model = R_GetModelByHandle( handle );
if(model->type == MOD_BRUSH)
{
VectorCopy( model->bmodel->bounds[0], mins );
VectorCopy( model->bmodel->bounds[1], maxs );
return;
}
else if (model->type == MOD_MESH)
{
md3Header_t* header = model->md3[0];
md3Frame_t* frame = (md3Frame_t *) ((unsigned char *)header + header->ofsFrames);
VectorCopy( frame->bounds[0], mins );
VectorCopy( frame->bounds[1], maxs );
return;
}
else if (model->type == MOD_MDR)
{
mdrHeader_t* header = (mdrHeader_t *)model->modelData;
mdrFrame_t* frame = (mdrFrame_t *) ((unsigned char *)header + header->ofsFrames);
VectorCopy( frame->bounds[0], mins );
VectorCopy( frame->bounds[1], maxs );
return;
}
else if(model->type == MOD_IQM)
{
iqmData_t* iqmData = model->modelData;
if(iqmData->bounds)
{
VectorCopy(iqmData->bounds, mins);
VectorCopy(iqmData->bounds + 3, maxs);
return;
}
}
VectorClear( mins );
VectorClear( maxs );
}

253
code/renderervk/R_Parser.c Normal file
View file

@ -0,0 +1,253 @@
#include "tr_local.h"
#include "ref_import.h"
/*
============================================================================
PARSING
split those parsing functions from q_shared.c
I want the render part standalone, dont fuck up with game part.
============================================================================
*/
static char r_parsename[512];
static int r_lines;
static int r_tokenline;
void R_BeginParseSession(const char* name)
{
r_lines = 1;
r_tokenline = 0;
snprintf(r_parsename, sizeof(r_parsename), "%s", name);
}
int R_GetCurrentParseLine( void )
{
if ( r_tokenline )
{
return r_tokenline;
}
return r_lines;
}
int R_Compress( char *data_p )
{
qboolean newline = qfalse;
qboolean whitespace = qfalse;
char* in = data_p;
char* out = data_p;
if (in)
{
int c;
while ((c = *in) != 0)
{
// skip double slash comments
if ( c == '/' && in[1] == '/' )
{
while (*in && *in != '\n') {
in++;
}
// skip /* */ comments
}
else if ( c == '/' && in[1] == '*' ) {
while ( *in && ( *in != '*' || in[1] != '/' ) )
in++;
if ( *in )
in += 2;
// record when we hit a newline
}
else if ( c == '\n' || c == '\r' ) {
newline = qtrue;
in++;
// record when we hit whitespace
}
else if ( (c == ' ') || (c == '\t') )
{
whitespace = qtrue;
in++;
// an actual token
}
else
{
// if we have a pending newline, emit it (and it counts as whitespace)
if (newline)
{
*out++ = '\n';
newline = qfalse;
whitespace = qfalse;
}
if (whitespace)
{
*out++ = ' ';
whitespace = qfalse;
}
// copy quoted strings unmolested
if (c == '"') {
*out++ = c;
in++;
while (1) {
c = *in;
if (c && c != '"') {
*out++ = c;
in++;
} else {
break;
}
}
if (c == '"') {
*out++ = c;
in++;
}
} else {
*out = c;
out++;
in++;
}
}
}
*out = 0;
}
return out - data_p;
}
/*
==============
Parse a token out of a string
Will never return NULL, just empty strings
If "allowLineBreaks" is qtrue then an empty
string will be returned if the next token is a newline.
==============
*/
char* R_ParseExt(char** data_p, qboolean allowLineBreaks)
{
unsigned int len = 0;
char *data = *data_p;
unsigned char c;
static char r_token[512] = {0};
r_token[0] = 0;
r_tokenline = 0;
// make sure incoming data is valid
if( !data )
{
*data_p = NULL;
return r_token;
}
while( 1 )
{
// skip whitespace
//data = SkipWhitespace( data, &hasNewLines );
while( (c = *data) <= ' ')
{
if( c == '\n' )
{
r_lines++;
if( allowLineBreaks == qfalse )
{
*data_p = data;
return r_token;
}
}
else if( c == 0 )
{
*data_p = NULL;
return r_token;
}
data++;
}
// skip double slash comments
if(data[0] == '/')
{
if(data[1] == '/')
{
data += 2;
while (*data && (*data != '\n'))
{
data++;
}
}
else if( data[1] == '*' )
{ // skip /* */ comments
data += 2;
// Assuming /* and */ occurs in pairs.
while( (data[0] != '*') || (data[1] != '/') )
{
if ( data[0] == '\n' )
{
r_lines++;
}
data++;
}
data += 2;
}
else
break;
}
else
break;
}
// token starts on this line
r_tokenline = r_lines;
// handle quoted strings
if (c == '\"')
{
data++;
while (1)
{
c = *data++;
if (c == '\"' || !c)
{
r_token[len] = 0;
*data_p = data;
return r_token;
}
else if ( c == '\n' )
{
r_lines++;
}
if (len < MAX_TOKEN_CHARS - 1)
{
r_token[len] = c;
len++;
}
}
}
// parse a regular word
do
{
if (len < MAX_TOKEN_CHARS - 1)
{
r_token[len++] = c;
}
c = *(++data);
} while(c > ' ');
r_token[len] = 0;
*data_p = data;
return r_token;
}

View file

@ -0,0 +1,10 @@
#ifndef R_PARSER_H_
#define R_PARSER_H_
char* R_ParseExt(char** data_p, qboolean allowLineBreaks);
int R_Compress( char *data_p );
int R_GetCurrentParseLine( void );
void R_BeginParseSession(const char* name);
#endif

View file

@ -0,0 +1,31 @@
#include "R_PortalPlane.h"
static struct rplane_s g_portalPlane; // clip anything behind this if mirroring
inline static float DotProduct( const float v1[3], const float v2[3] )
{
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
void R_SetupPortalPlane(const float axis[3][3], const float origin[3])
{
// VectorSubtract( vec3_origin, pCamera->axis[0], g_portalPlane.normal );
// g_portalPlane.dist = DotProduct( pCamera->origin, g_portalPlane.normal );
g_portalPlane.normal[0] = - axis[0][0];
g_portalPlane.normal[1] = - axis[0][1];
g_portalPlane.normal[2] = - axis[0][2];
g_portalPlane.dist = - origin[0] * axis[0][0]
- origin[1] * axis[0][1]
- origin[2] * axis[0][2];
}
void R_TransformPlane(const float R[3][3], const float T[3], struct rplane_s* pDstPlane)
{
pDstPlane->normal[0] = DotProduct (R[0], g_portalPlane.normal);
pDstPlane->normal[1] = DotProduct (R[1], g_portalPlane.normal);
pDstPlane->normal[2] = DotProduct (R[2], g_portalPlane.normal);
pDstPlane->dist = DotProduct (T, g_portalPlane.normal) - g_portalPlane.dist;
}

View file

@ -0,0 +1,16 @@
#ifndef R_PORTAL_PLANE_H_
#define R_PORTAL_PLANE_H_
struct rplane_s {
float normal[3];
float dist;
};
// extern struct rplane_s g_portalPlane; // clip anything behind this if mirroring
void R_SetupPortalPlane(const float axis[3][3], const float origin[3]);
void R_TransformPlane(const float R[3][3], const float T[3], struct rplane_s* pDstPlane);
#endif

View file

@ -0,0 +1,42 @@
#include <stdio.h>
#include <stdlib.h>
#include "R_PrintMat.h"
#include "ref_import.h"
/*
* ===============================================================================
* Filename: R_PrintMat.h
*
* Description: print matrix values or buffer in easier way for debug
* Author: SuiJingfeng, 18949883232@163.com
* ===============================================================================
*/
void printMat1x3f(const char* name, const float src[3])
{
ri.Printf(PRINT_ALL, "\n float %s[3] = {%f, %f, %f};\n",
name, src[0], src[1], src[2]);
}
void printMat1x4f(const char* name, const float src[4])
{
ri.Printf(PRINT_ALL, "\n float %s[4] = {%f, %f, %f, %f};\n",
name, src[0], src[1], src[2], src[3]);
}
void printMat3x3f(const char* name, const float src[3][3])
{
ri.Printf(PRINT_ALL,
"\n float %s[3][3] = {\n%f, %f, %f, \n%f, %f, %f, \n%f, %f, %f };\n", name,
src[0][0], src[0][1], src[0][2],
src[1][0], src[1][1], src[1][2],
src[2][0], src[2][1], src[2][2]);
}
void printMat4x4f(const char* name, const float src[16])
{
ri.Printf(PRINT_ALL, "\n float %s[16] = {\n %f, %f, %f, %f,\n %f, %f, %f, %f, \n %f, %f, %f, %f, \n %f, %f, %f, %f};\n", name,
src[0], src[1], src[2], src[3], src[4], src[5], src[6], src[7],
src[8], src[9], src[10], src[11], src[12], src[13], src[14], src[15] );
}

View file

@ -0,0 +1,21 @@
/*
* ==================================================================================
*
* Filename: R_PrintMat.h
*
* Description: print matrix values for debug
* Author: Sui Jingfeng (), 18949883232@163.com
* ==================================================================================
*/
#ifndef R_PRINT_MAT_H_
#define R_PRINT_MAT_H_
// data print helper
void printMat1x3f(const char* name, const float src[3]);
void printMat1x4f(const char* name, const float src[4]);
void printMat3x3f(const char* name, const float src[3][3]);
void printMat4x4f(const char* name, const float src[16]);
#endif

View file

@ -0,0 +1,43 @@
#include "ref_import.h"
#include "tr_globals.h"
extern void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
extern void RE_StretchPic ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, qhandle_t hShader );
/*
=============
FIXME: not exactly backend
Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
Used for cinematics.
=============
*/
void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const unsigned char *data, int client, qboolean dirty)
{
int i, j;
if ( !tr.registered ) {
return;
}
// make sure rows and cols are powers of 2
for ( i = 0 ; ( 1 << i ) < cols ; i++ )
{
;
}
for ( j = 0 ; ( 1 << j ) < rows ; j++ )
{
;
}
if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
}
RE_UploadCinematic(w, h, cols, rows, data, client, dirty);
tr.cinematicShader->stages[0]->bundle[0].image[0] = tr.scratchImage[client];
RE_StretchPic(x, y, w, h, 0.5f / cols, 0.5f / rows, 1.0f - 0.5f / cols, 1.0f - 0.5 / rows, tr.cinematicShader->index);
}

26
code/renderervk/VKimpl.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef VKIMPL_H_
#define VKIMPL_H_
/*
====================================================================
IMPLEMENTATION SPECIFIC FUNCTIONS
====================================================================
*/
#define VK_NO_PROTOTYPES
#include "vulkan/vulkan.h"
void vk_createWindow(void);
void vk_destroyWindow(void);
void vk_getInstanceProcAddrImpl(void);
void vk_createSurfaceImpl(void);
void vk_minimizeWindow( void );
#endif

346
code/renderervk/glConfig.c Normal file
View file

@ -0,0 +1,346 @@
#include "tr_local.h"
#include "ref_import.h"
#include "tr_cvar.h"
#include "../renderercommon/tr_types.h"
#include "VKimpl.h"
#include "vk_instance.h"
#include "vk_image.h"
// outside of this file shouldn't modify glConfig
// I want keep it locally, as it belong to OpenGL, not VulKan
// have to use this keep backward Compatibility
static glconfig_t glConfig;
static cvar_t* r_customwidth;
static cvar_t* r_customheight;
static cvar_t* r_customaspect;
typedef struct vidmode_s
{
const char *description;
int width, height;
float pixelAspect; // pixel width / height
} vidmode_t;
static const vidmode_t r_vidModes[] =
{
{ "Mode 0: 320x240", 320, 240, 1 },
{ "Mode 1: 400x300", 400, 300, 1 },
{ "Mode 2: 512x384", 512, 384, 1 },
{ "Mode 3: 640x480 (480p)", 640, 480, 1 },
{ "Mode 4: 800x600", 800, 600, 1 },
{ "Mode 5: 960x720", 960, 720, 1 },
{ "Mode 6: 1024x768", 1024, 768, 1 },
{ "Mode 7: 1152x864", 1152, 864, 1 },
{ "Mode 8: 1280x1024", 1280, 1024, 1 },
{ "Mode 9: 1600x1200", 1600, 1200, 1 },
{ "Mode 10: 2048x1536", 2048, 1536, 1 },
{ "Mode 11: 856x480", 856, 480, 1 }, // Q3 MODES END HERE AND EXTENDED MODES BEGIN
{ "Mode 12: 1280x720 (720p)", 1280, 720, 1 },
{ "Mode 13: 1280x768", 1280, 768, 1 },
{ "Mode 14: 1280x800", 1280, 800, 1 },
{ "Mode 15: 1280x960", 1280, 960, 1 },
{ "Mode 16: 1360x768", 1360, 768, 1 },
{ "Mode 17: 1366x768", 1366, 768, 1 }, // yes there are some out there on that extra 6
{ "Mode 18: 1360x1024", 1360, 1024, 1 },
{ "Mode 19: 1400x1050", 1400, 1050, 1 },
{ "Mode 20: 1400x900", 1400, 900, 1 },
{ "Mode 21: 1600x900", 1600, 900, 1 },
{ "Mode 22: 1680x1050", 1680, 1050, 1 },
{ "Mode 23: 1920x1080 (1080p)", 1920, 1080, 1 },
{ "Mode 24: 1920x1200", 1920, 1200, 1 },
{ "Mode 25: 1920x1440", 1920, 1440, 1 },
{ "Mode 26: 2560x1080", 2560, 1080, 1 },
{ "Mode 27: 2560x1600", 2560, 1600, 1 },
{ "Mode 28: 3840x2160 (4K)", 3840, 2160, 1 }
};
static const int s_numVidModes = 29;
void R_DisplayResolutionList_f( void )
{
int i;
ri.Printf( PRINT_ALL, "\n" );
for ( i = 0; i < s_numVidModes; i++ )
{
ri.Printf( PRINT_ALL, "%s\n", r_vidModes[i].description );
}
ri.Printf( PRINT_ALL, "\n" );
}
void R_SetWinMode(int mode, unsigned int width, unsigned int height, unsigned int hz)
{
if ( mode < -2 || mode >= s_numVidModes) {
mode = 3;
}
if (mode == -2)
{
// use desktop video resolution
glConfig.vidWidth = width;
glConfig.vidHeight = height;
glConfig.windowAspect = (float)width / (float)height;
glConfig.displayFrequency = hz;
glConfig.isFullscreen = 1;
}
else if ( mode == -1 )
{
glConfig.vidWidth = r_customwidth->integer;
glConfig.vidHeight = r_customheight->integer;
glConfig.windowAspect = r_customaspect->value;
glConfig.displayFrequency = 60;
glConfig.isFullscreen = 0;
}
else
{
glConfig.vidWidth = r_vidModes[mode].width;
glConfig.vidHeight = r_vidModes[mode].height;
glConfig.windowAspect = (float)r_vidModes[mode].width / ( r_vidModes[mode].height * r_vidModes[mode].pixelAspect );
glConfig.displayFrequency = 60;
glConfig.isFullscreen = 0;
}
ri.Printf(PRINT_ALL, " MODE: %d, %d x %d, refresh rate: %dhz\n",
mode, glConfig.vidWidth, glConfig.vidHeight, glConfig.displayFrequency);
}
void R_GetWinResolution(int* w, int* h)
{
*w = glConfig.vidWidth;
*h = glConfig.vidHeight;
}
void R_GetWinResolutionF(float* w, float* h)
{
*w = glConfig.vidWidth;
*h = glConfig.vidHeight;
}
void R_InitDisplayResolution( void )
{
// leilei - -2 is so convenient for modern day PCs
r_mode = ri.Cvar_Get( "r_mode", "-2", CVAR_ARCHIVE | CVAR_LATCH );
r_customwidth = ri.Cvar_Get( "r_customwidth", "960", CVAR_ARCHIVE | CVAR_LATCH );
r_customheight = ri.Cvar_Get( "r_customheight", "540", CVAR_ARCHIVE | CVAR_LATCH );
r_customaspect = ri.Cvar_Get( "r_customaspect", "1.78", CVAR_ARCHIVE | CVAR_LATCH );
}
void R_glConfigClear(void)
{
memset(&glConfig, 0, sizeof(glConfig));
}
//IN: a pointer to the glConfig struct
void R_GetGlConfig(glconfig_t * const pCfg)
{
*pCfg = glConfig;
}
void R_glConfigInit(void)
{
ri.Printf(PRINT_ALL, "--- R_glConfigInit() ---\n");
// These values force the UI to disable driver selection
glConfig.driverType = GLDRV_ICD;
glConfig.hardwareType = GLHW_GENERIC;
// Only using SDL_SetWindowBrightness to determine if hardware gamma is supported
glConfig.deviceSupportsGamma = qtrue;
glConfig.textureEnvAddAvailable = 0; // not used
glConfig.textureCompression = TC_NONE; // not used
// init command buffers and SMP
glConfig.stereoEnabled = 0;
glConfig.smpActive = qfalse; // not used
// hardcode it
glConfig.colorBits = 32;
glConfig.depthBits = 24;
glConfig.stencilBits = 8;
}
// ==================================================
// ==================================================
static void printDeviceExtensions(void)
{
uint32_t nDevExts = 0;
// To query the extensions available to a given physical device
VK_CHECK( qvkEnumerateDeviceExtensionProperties( vk.physical_device, NULL, &nDevExts, NULL) );
assert(nDevExts > 0);
VkExtensionProperties* pDevExt =
(VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * nDevExts);
qvkEnumerateDeviceExtensionProperties(
vk.physical_device, NULL, &nDevExts, pDevExt);
ri.Printf(PRINT_ALL, "--------- Total %d Device Extension Supported ---------\n", nDevExts);
uint32_t i;
for (i=0; i<nDevExts; ++i)
{
ri.Printf(PRINT_ALL, " %s \n", pDevExt[i].extensionName);
}
ri.Printf(PRINT_ALL, "--------- ----------------------------------- ---------\n");
free(pDevExt);
}
static void printInstanceExtensions(int setting)
{
uint32_t i = 0;
uint32_t nInsExt = 0;
// To retrieve a list of supported extensions before creating an instance
VK_CHECK( qvkEnumerateInstanceExtensionProperties( NULL, &nInsExt, NULL) );
assert(nInsExt > 0);
VkExtensionProperties* pInsExt = (VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * nInsExt);
VK_CHECK(qvkEnumerateInstanceExtensionProperties( NULL, &nInsExt, pInsExt));
ri.Printf(PRINT_ALL, "\n");
ri.Printf(PRINT_ALL, "----- Total %d Instance Extension Supported -----\n", nInsExt);
for (i = 0; i < nInsExt; ++i)
{
ri.Printf(PRINT_ALL, "%s\n", pInsExt[i].extensionName );
}
ri.Printf(PRINT_ALL, "----- ------------------------------------- -----\n\n");
// =================================================================
// we enabled all the instance extenstion, dose this reasonable???
// so we copy it to glConfig.ext str,
// split it with create instance function so that made it clear and clean
if( setting )
{
uint32_t indicator = 0;
for (i = 0; i < nInsExt; ++i)
{
uint32_t len = strlen(pInsExt[i].extensionName);
memcpy(glConfig.extensions_string + indicator,
pInsExt[i].extensionName, len);
indicator += len;
glConfig.extensions_string[indicator++] = ' ';
}
free(pInsExt);
}
// ==================================================================
/*
uint32_t nDevExts = 0;
// To query the extensions available to a given physical device
VK_CHECK( qvkEnumerateDeviceExtensionProperties( vk.physical_device, NULL, &nDevExts, NULL) );
assert(nDevExts > 0);
VkExtensionProperties* pDevExt =
(VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * nDevExts);
qvkEnumerateDeviceExtensionProperties(
vk.physical_device, NULL, &nDevExts, pDevExt);
ri.Printf(PRINT_ALL, "---- Total %d Device Extension Supported ----\n", nDevExts);
uint32_t i;
for (i=0; i<nDevExts; ++i)
{
ri.Printf(PRINT_ALL, " %s \n", pDevExt[i].extensionName);
}
ri.Printf(PRINT_ALL, "---- ----------------------------------- ----\n\n");
// There much more device extentions, beyound UI driver info can display
// and we only use VK_KHR_swapchain for now, so won't copy that,
// just print it out.
for (i = 0; i < nDevExts; ++i)
{
uint32_t len = strlen(pDevExt[i].extensionName);
memcpy(glConfig.extensions_string + indicator, pDevExt[i].extensionName, len);
indicator += len;
glConfig.extensions_string[indicator++] = ' ';
}
free(pDevExt);
*/
}
void vulkanInfo_f( void )
{
ri.Printf( PRINT_ALL, "\nActive 3D API: Vulkan\n" );
// To query general properties of physical devices once enumerated
VkPhysicalDeviceProperties props;
qvkGetPhysicalDeviceProperties(vk.physical_device, &props);
uint32_t major = VK_VERSION_MAJOR(props.apiVersion);
uint32_t minor = VK_VERSION_MINOR(props.apiVersion);
uint32_t patch = VK_VERSION_PATCH(props.apiVersion);
const char* device_type;
if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
device_type = "INTEGRATED_GPU";
else if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
device_type = "DISCRETE_GPU";
else if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)
device_type = "VIRTUAL_GPU";
else if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
device_type = "CPU";
else
device_type = "Unknown";
const char* vendor_name = "unknown";
if (props.vendorID == 0x1002) {
vendor_name = "Advanced Micro Devices, Inc.";
} else if (props.vendorID == 0x10DE) {
vendor_name = "NVIDIA";
} else if (props.vendorID == 0x8086) {
vendor_name = "Intel Corporation";
}
ri.Printf(PRINT_ALL, "Vk api version: %d.%d.%d\n", major, minor, patch);
ri.Printf(PRINT_ALL, "Vk driver version: %d\n", props.driverVersion);
ri.Printf(PRINT_ALL, "Vk vendor id: 0x%X (%s)\n", props.vendorID, vendor_name);
ri.Printf(PRINT_ALL, "Vk device id: 0x%X\n", props.deviceID);
ri.Printf(PRINT_ALL, "Vk device type: %s\n", device_type);
ri.Printf(PRINT_ALL, "Vk device name: %s\n", props.deviceName);
//
char tmpBuf[128] = {0};
snprintf(tmpBuf, 128, " Vk api version: %d.%d.%d ", major, minor, patch);
strncpy( glConfig.version_string, tmpBuf, sizeof( glConfig.version_string ) );
strncpy( glConfig.vendor_string, vendor_name, sizeof( glConfig.vendor_string ) );
strncpy( glConfig.renderer_string, props.deviceName, sizeof( glConfig.renderer_string ) );
if (*glConfig.renderer_string &&
glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
//
// Info that for UI display
//
printInstanceExtensions(1);
printDeviceExtensions();
gpuMemUsageInfo_f();
}

View file

@ -0,0 +1,16 @@
#ifndef GL_CONFIGURE_H_
#define GL_CONFIGURE_H_
void R_SetWinMode(int mode, unsigned int w, unsigned int h, unsigned int hz);
void R_glConfigInit(void);
void R_glConfigClear(void);
void R_GetWinResolution(int* w, int* h);
void R_GetWinResolutionF(float* w, float* h);
void R_GetGlConfig(glconfig_t * const pOut);
void R_DisplayResolutionList_f(void);
void R_InitDisplayResolution( void );
void vulkanInfo_f( void );
#endif

132
code/renderervk/icon_oa.h Normal file
View file

@ -0,0 +1,132 @@
/* GIMP RGBA C-Source image dump (sdl_icon.h) */
static const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */
unsigned char pixel_data[32 * 32 * 4 + 1];
} CLIENT_WINDOW_ICON = {
32, 32, 4,
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377w\0\0"
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0"
"\0\377w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\210\0\0\377"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\210\0\0\377\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\210\0\0"
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\252\0\0"
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\210\0\0\377\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\252\0\0\377\0\0\0\0\273\0\0\377\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\231\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\273\0\0\377\314\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\231\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0"
"\377\314\0\0\377\0\0\0\0\335\0\0\377\314\0\0\377\231\0\0\377\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\231\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\314\0\0\377\335"
"\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\231\0\0\377\314\0\0\377\335\0\0\377\335"
"\0\0\377\273\0\0\377\231\0\0\377\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\231\0\0\377\252\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\252\0\0\377\273\0\0\377\335\0\0\377\335\0\0"
"\377\314\0\0\377\231\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\252\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377"
"\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377\0\0\0\0\252\0\0\377\252"
"\0\0\377\0\0\0\0\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0\377\314\0\0"
"\377\314\0\0\377\314\0\0\377\314\0\0\377\252\0\0\377\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\210\0\0\377\231\0\0\377\273\0\0\377\314\0\0\377\314"
"\0\0\377\0\0\0\0\252\0\0\377\252\0\0\377\0\0\0\0\314\0\0\377\314\0\0\377"
"\273\0\0\377\231\0\0\377\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377"
"\273\0\0\377\0\0\0\0\252\0\0\377\252\0\0\377\0\0\0\0\273\0\0\377\210\0\0"
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377\273\0\0\377"
"\0\0\0\0\231\0\0\377\252\0\0\377\0\0\0\0\273\0\0\377w\0\0\377\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\252\0\0\377\0\0\0\0\231\0\0"
"\377\231\0\0\377\0\0\0\0\252\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\252\0\0\377\0\0\0\0\210\0\0\377\231\0\0\377"
"\0\0\0\0\252\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\231\0\0\377\0\0\0\0\210\0\0\377\210\0\0\377\0\0\0\0\231\0\0"
"\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\231"
"\0\0\377\0\0\0\0w\0\0\377\210\0\0\377\0\0\0\0\231\0\0\377\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\0\0\0\0\210"
"\0\0\377\210\0\0\377\0\0\0\0\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\210\0\0\377\0\0\0\0w\0\0\377\210\0\0\377"
"\0\0\0\0\210\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0w\0\0\377\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0w\0\0\377\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377\0\0\0\0"
"w\0\0\377w\0\0\377\0\0\0\0w\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0w\0\0\377\0\0\0\0w\0\0\377w\0\0\377\0\0\0\0w\0"
"\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0f\0\0\377f\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0f\0\0\377f\0\0\377"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0",
};

View file

@ -0,0 +1,20 @@
#ifndef IMAGE_LOADER_H_
#define IMAGE_LOADER_H_
/*
=============================================================
IMAGE LOADERS
=============================================================
*/
void R_LoadBMP( const char *name, byte **pic, int *width, int *height );
void R_LoadJPG( const char *name, byte **pic, int *width, int *height );
void R_LoadPCX( const char *name, byte **pic, int *width, int *height );
void R_LoadPNG( const char *name, byte **pic, int *width, int *height );
void R_LoadTGA( const char *name, byte **pic, int *width, int *height );
#endif

View file

@ -0,0 +1,567 @@
/*
* =========================================================================
* Filename: matrix_multiplication.c
* Description: 4*4 matrix
* =========================================================================
*/
#if defined __x86_64__
#include <xmmintrin.h>
#endif
#include <string.h>
#include <math.h>
#include "ref_import.h"
#include "matrix_multiplication.h"
#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F )
static const float s_Identity3x3[3][3] = {
{ 1.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f }
};
static const float s_Identity4x4[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 Mat4Copy( const float in[64], float out[16] )
{
memcpy(out, in, 64);
}
void Mat3x3Copy( float dst[3][3], const float src[3][3] )
{
memcpy(dst, src, 36);
}
void VectorLerp( float a[3], float b[3], float lerp, float out[3])
{
out[0] = a[0] + (b[0] - a[0]) * lerp;
out[1] = a[1] + (b[1] - a[1]) * lerp;
out[2] = a[2] + (b[2] - a[2]) * lerp;
}
void VectorNorm( float v[3] )
{
float length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
if(length != 0)
{
/* writing it this way allows gcc to recognize that rsqrt can be used */
length = 1.0f / sqrtf (length);
v[0] *= length;
v[1] *= length;
v[2] *= length;
}
}
float VectorLen( const float v[3] )
{
return sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
}
void Mat4Identity( float out[16] )
{
memcpy(out, s_Identity4x4, 64);
}
void Mat4Translation( float vec[3], float out[16] )
{
memcpy(out, s_Identity4x4, 64);
out[12] = vec[0];
out[13] = vec[1];
out[14] = vec[2];
}
//
// NOTE; out = b * a ???
// a, b and c are specified in column-major order
//
void myGlMultMatrix(const float A[16], const float B[16], float out[16])
{
int i, j;
for ( i = 0 ; i < 4 ; i++ )
{
for ( j = 0 ; j < 4 ; j++ )
{
out[ i * 4 + j ] =
A [ i * 4 + 0 ] * B [ 0 * 4 + j ]
+ A [ i * 4 + 1 ] * B [ 1 * 4 + j ]
+ A [ i * 4 + 2 ] * B [ 2 * 4 + j ]
+ A [ i * 4 + 3 ] * B [ 3 * 4 + j ];
}
}
}
void MatrixMultiply4x4(const float A[16], const float B[16], float out[16])
{
out[0] = A[0]*B[0] + A[1]*B[4] + A[2]*B[8] + A[3]*B[12];
out[1] = A[0]*B[1] + A[1]*B[5] + A[2]*B[9] + A[3]*B[13];
out[2] = A[0]*B[2] + A[1]*B[6] + A[2]*B[10] + A[3]*B[14];
out[3] = A[0]*B[3] + A[1]*B[7] + A[2]*B[11] + A[3]*B[15];
out[4] = A[4]*B[0] + A[5]*B[4] + A[6]*B[8] + A[7]*B[12];
out[5] = A[4]*B[1] + A[5]*B[5] + A[6]*B[9] + A[7]*B[13];
out[6] = A[4]*B[2] + A[5]*B[6] + A[6]*B[10] + A[7]*B[14];
out[7] = A[4]*B[3] + A[5]*B[7] + A[6]*B[11] + A[7]*B[15];
out[8] = A[8]*B[0] + A[9]*B[4] + A[10]*B[8] + A[11]*B[12];
out[9] = A[8]*B[1] + A[9]*B[5] + A[10]*B[9] + A[11]*B[13];
out[10] = A[8]*B[2] + A[9]*B[6] + A[10]*B[10] + A[11]*B[14];
out[11] = A[8]*B[3] + A[9]*B[7] + A[10]*B[11] + A[11]*B[15];
out[12] = A[12]*B[0] + A[13]*B[4] + A[14]*B[8] + A[15]*B[12];
out[13] = A[12]*B[1] + A[13]*B[5] + A[14]*B[9] + A[15]*B[13];
out[14] = A[12]*B[2] + A[13]*B[6] + A[14]*B[10] + A[15]*B[14];
out[15] = A[12]*B[3] + A[13]*B[7] + A[14]*B[11] + A[15]*B[15];
}
/*
* NOTE; out = B * A in math
* a, b and c are specified in column-major order
* out must be 16 byte aliagned
*/
void MatrixMultiply4x4_SSE(const float A[16], const float B[16], float out[16])
{
#if defined __x86_64__
__m128 row1 = _mm_load_ps(&B[0]);
__m128 row2 = _mm_load_ps(&B[4]);
__m128 row3 = _mm_load_ps(&B[8]);
__m128 row4 = _mm_load_ps(&B[12]);
int i;
for(i=0; i<4; i++)
{
__m128 brod1 = _mm_set1_ps(A[4*i ]);
__m128 brod2 = _mm_set1_ps(A[4*i + 1]);
__m128 brod3 = _mm_set1_ps(A[4*i + 2]);
__m128 brod4 = _mm_set1_ps(A[4*i + 3]);
__m128 row = _mm_add_ps(
_mm_add_ps( _mm_mul_ps(brod1, row1), _mm_mul_ps(brod2, row2) ),
_mm_add_ps( _mm_mul_ps(brod3, row3), _mm_mul_ps(brod4, row4) )
);
_mm_store_ps(&out[4*i], row);
}
#else
MatrixMultiply4x4( A, B, out);
#endif
}
void Mat4Transform( const float in1[16], const float in2[4], float out[4] )
{
// 16 mult, 12 plus
float a = in2[0];
float b = in2[1];
float c = in2[2];
float d = in2[3];
out[0] = in1[0] * a + in1[4] * b + in1[ 8] * c + in1[12] * d;
out[1] = in1[1] * a + in1[5] * b + in1[ 9] * c + in1[13] * d;
out[2] = in1[2] * a + in1[6] * b + in1[10] * c + in1[14] * d;
out[3] = in1[3] * a + in1[7] * b + in1[11] * c + in1[15] * d;
}
void Vec3Transform(const float Mat[16], const float v[3], float out[3])
{
float x = v[0];
float y = v[1];
float z = v[2];
out[0] = Mat[0] * x + Mat[4] * y + Mat[ 8] * z + Mat[12];
out[1] = Mat[1] * x + Mat[5] * y + Mat[ 9] * z + Mat[13];
out[2] = Mat[2] * x + Mat[6] * y + Mat[10] * z + Mat[14];
}
// unfortunately, this fun seems not faseter than Mat4Transform
// vector1x4 * mat4x4
void Mat4x1Transform_SSE( const float A[16], const float x[4], float out[4] )
{
// 16 mult, 12 plus
//out[0] = A[0] * x[0] + A[4] * x[1] + A[ 8] * x[2] + A[12] * x[3];
//out[1] = A[1] * x[0] + A[5] * x[1] + A[ 9] * x[2] + A[13] * x[3];
//out[2] = A[2] * x[0] + A[6] * x[1] + A[10] * x[2] + A[14] * x[3];
//out[3] = A[3] * x[0] + A[7] * x[1] + A[11] * x[2] + A[15] * x[3];
// 4 mult + 3 plus + 4 broadcast + 8 load (4 _mm_set1_ps + 4 _mm_set1_ps)
// + 1 store
#if defined __x86_64__
__m128 r1 = _mm_mul_ps( _mm_set1_ps(x[0]), _mm_load_ps(A ) );
__m128 r2 = _mm_mul_ps( _mm_set1_ps(x[1]), _mm_load_ps(A+4 ) );
__m128 r3 = _mm_mul_ps( _mm_set1_ps(x[2]), _mm_load_ps(A+8 ) );
__m128 r4 = _mm_mul_ps( _mm_set1_ps(x[3]), _mm_load_ps(A+12) );
_mm_store_ps(out, _mm_add_ps( _mm_add_ps(r1, r2), _mm_add_ps(r3, r4) ) );
#else
Mat4Transform(A, x, out);
#endif
}
/*
#define SHUFFLE_PARAM(x, y, z, w) ( x | y<<2 | z<<4 | w<<6 )
#define _mm_replicate_x_ps(v) _mm_shuffle_ps(v, v, SHUFFLE_PARAM(0, 0, 0, 0))
#define _mm_replicate_y_ps(v) _mm_shuffle_ps(v, v, SHUFFLE_PARAM(1, 1, 1, 1))
#define _mm_replicate_z_ps(v) _mm_shuffle_ps(v, v, SHUFFLE_PARAM(2, 2, 2, 2))
#define _mm_replicate_w_ps(v) _mm_shuffle_ps(v, v, SHUFFLE_PARAM(3, 3, 3, 3))
void Vec4Transform_SSE( const float A[16], float v[4], float out[4] )
{
#if defined __x86_64__
__m128 x = _mm_load_ps(v);
// 16 mult, 12 plus
//out[0] = A[0] * x[0] + A[4] * x[1] + A[ 8] * x[2] + A[12] * x[3];
//out[1] = A[1] * x[0] + A[5] * x[1] + A[ 9] * x[2] + A[13] * x[3];
//out[2] = A[2] * x[0] + A[6] * x[1] + A[10] * x[2] + A[14] * x[3];
//out[3] = A[3] * x[0] + A[7] * x[1] + A[11] * x[2] + A[15] * x[3];
// 4 mult + 3 plus + 4 broadcast + 8 load (4 _mm_set1_ps + 4 _mm_set1_ps)
// + 1 store
__m128 r1 = _mm_mul_ps( _mm_replicate_x_ps( x ), _mm_load_ps(A) );
__m128 r2 = _mm_mul_ps( _mm_replicate_y_ps( x ), _mm_load_ps(A+4) );
__m128 r3 = _mm_mul_ps( _mm_replicate_z_ps( x ), _mm_load_ps(A+8) );
__m128 r4 = _mm_mul_ps( _mm_replicate_w_ps( x ), _mm_load_ps(A+12) );
_mm_store_ps(out, _mm_add_ps( _mm_add_ps( r1, r2 ), _mm_add_ps( r3, r4 ) ));
#else
Mat4Transform(A, v, out);
#endif
}
*/
void Mat3x3Identity( float pMat[3][3] )
{
memcpy(pMat, s_Identity3x3, 36);
}
void TransformModelToClip( const float src[3], const float* pMatModel, const float* pMatProj, float eye[4], float dst[4])
{
int i;
for ( i = 0 ; i < 4 ; i++ )
{
eye[i] =
src[0] * pMatModel[ i + 0 * 4 ] +
src[1] * pMatModel[ i + 1 * 4 ] +
src[2] * pMatModel[ i + 2 * 4 ] +
1 * pMatModel[ i + 3 * 4 ];
}
for ( i = 0 ; i < 4 ; i++ )
{
dst[i] =
eye[0] * pMatProj[ i + 0 * 4 ] +
eye[1] * pMatProj[ i + 1 * 4 ] +
eye[2] * pMatProj[ i + 2 * 4 ] +
eye[3] * pMatProj[ i + 3 * 4 ];
}
}
void VectorCross( const float v1[3], const float v2[3], float cross[3] )
{
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
// fast vector normalize routine that does not check to make sure
// that length != 0, nor does it return length, uses rsqrt approximation
void FastNormalize1f(float v[3])
{
// writing it this way allows gcc to recognize that rsqrt can be used
float invLen = 1.0f / sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
v[0] = v[0] * invLen;
v[1] = v[1] * invLen;
v[2] = v[2] * invLen;
}
void FastNormalize2f( const float* v, float* out)
{
// writing it this way allows gcc to recognize that rsqrt can be used
float invLen = 1.0f / sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
out[0] = v[0] * invLen;
out[1] = v[1] * invLen;
out[2] = v[2] * invLen;
}
// use Rodrigue's rotation formula
// dir are not assumed to be unit vector
void PointRotateAroundVector(float* res, const float* vec, const float* p, const float degrees)
{
float rad = DEG2RAD( degrees );
float cos_th = cos( rad );
float sin_th = sin( rad );
float k[3];
// writing it this way allows gcc to recognize that rsqrt can be used
float invLen = 1.0f / sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
k[0] = vec[0] * invLen;
k[1] = vec[1] * invLen;
k[2] = vec[2] * invLen;
float d = (1 - cos_th) * (p[0] * k[0] + p[1] * k[1] + p[2] * k[2]);
res[0] = sin_th * (k[1]*p[2] - k[2]*p[1]);
res[1] = sin_th * (k[2]*p[0] - k[0]*p[2]);
res[2] = sin_th * (k[0]*p[1] - k[1]*p[0]);
res[0] += cos_th * p[0] + d * k[0];
res[1] += cos_th * p[1] + d * k[1];
res[2] += cos_th * p[2] + d * k[2];
}
// vector k are assumed to be unit
void RotateAroundUnitVector(float* res, const float* k, const float* p, const float degrees)
{
float rad = DEG2RAD( degrees );
float cos_th = cos( rad );
float sin_th = sin( rad );
float d = (1 - cos_th) * (p[0] * k[0] + p[1] * k[1] + p[2] * k[2]);
res[0] = sin_th * (k[1]*p[2] - k[2]*p[1]);
res[1] = sin_th * (k[2]*p[0] - k[0]*p[2]);
res[2] = sin_th * (k[0]*p[1] - k[1]*p[0]);
res[0] += cos_th * p[0] + d * k[0];
res[1] += cos_th * p[1] + d * k[1];
res[2] += cos_th * p[2] + d * k[2];
}
// note: vector forward are NOT assumed to be nornalized,
// unit: nornalized of forward,
// dst: unit vector which perpendicular of forward(src)
void VectorPerp( const float src[3], float dst[3] )
{
float unit[3];
float sqlen = src[0]*src[0] + src[1]*src[1] + src[2]*src[2];
if(0 == sqlen)
{
ri.Printf( PRINT_WARNING, "MakePerpVectors: zero vertor input!\n");
return;
}
dst[1] = -src[0];
dst[2] = src[1];
dst[0] = src[2];
// this rotate and negate try to make a vector not colinear with the original
// actually can not guarantee, for example
// forward = (1/sqrt(3), 1/sqrt(3), -1/sqrt(3)),
// then right = (-1/sqrt(3), -1/sqrt(3), 1/sqrt(3))
float invLen = 1.0f / sqrtf(sqlen);
unit[0] = src[0] * invLen;
unit[1] = src[1] * invLen;
unit[2] = src[2] * invLen;
float d = DotProduct(unit, dst);
dst[0] -= d*unit[0];
dst[1] -= d*unit[1];
dst[2] -= d*unit[2];
// normalize the result
invLen = 1.0f / sqrtf(dst[0]*dst[0] + dst[1]*dst[1] + dst[2]*dst[2]);
dst[0] *= invLen;
dst[1] *= invLen;
dst[2] *= invLen;
}
// Given a normalized forward vector, create two other perpendicular vectors
// note: vector forward are NOT assumed to be nornalized,
// after this funtion is called , forward are nornalized.
// right, up: perpendicular of forward
float MakeTwoPerpVectors(const float forward[3], float right[3], float up[3])
{
float sqLen = forward[0]*forward[0]+forward[1]*forward[1]+forward[2]*forward[2];
if(sqLen)
{
float nf[3] = {0, 0, 1};
float invLen = 1.0f / sqrtf(sqLen);
nf[0] = forward[0] * invLen;
nf[1] = forward[1] * invLen;
nf[2] = forward[2] * invLen;
float adjlen = DotProduct(nf, right);
// this rotate and negate guarantees a vector
// not colinear with the original
right[0] = forward[2] - adjlen * nf[0];
right[1] = -forward[0] - adjlen * nf[1];
right[2] = forward[1] - adjlen * nf[2];
invLen = 1.0f/sqrtf(right[0]*right[0]+right[1]*right[1]+right[2]*right[2]);
right[0] *= invLen;
right[1] *= invLen;
right[2] *= invLen;
// get the up vector with the right hand rules
VectorCross(right, nf, up);
return (sqLen * invLen);
}
return 0;
}
void TransformModelToClip_SSE( const float src[3], const float pMatModel[16], const float pMatProj[16], float dst[4] )
{
#if defined __x86_64__
float AugSrc[4] = {src[0], src[1], src[2], 1.0f};
__m128 row1 = _mm_load_ps(&pMatProj[0]);
__m128 row2 = _mm_load_ps(&pMatProj[4]);
__m128 row3 = _mm_load_ps(&pMatProj[8]);
__m128 row4 = _mm_load_ps(&pMatProj[12]);
__m128 res[4];
int i;
for(i=0; i<4; i++)
{
__m128 brod1 = _mm_set1_ps(pMatModel[4*i ]);
__m128 brod2 = _mm_set1_ps(pMatModel[4*i + 1]);
__m128 brod3 = _mm_set1_ps(pMatModel[4*i + 2]);
__m128 brod4 = _mm_set1_ps(pMatModel[4*i + 3]);
__m128 scol = _mm_set1_ps(AugSrc[i]);
res[i] =_mm_mul_ps( _mm_add_ps(
_mm_add_ps( _mm_mul_ps(brod1, row1), _mm_mul_ps(brod2, row2) ),
_mm_add_ps( _mm_mul_ps(brod3, row3), _mm_mul_ps(brod4, row4) )
), scol);
}
_mm_store_ps(dst, _mm_add_ps( _mm_add_ps(res[0], res[1]), _mm_add_ps(res[2], res[3]) ) );
#else
float eye[4];
TransformModelToClip(src, pMatModel, pMatProj, eye, dst );
#endif
// print4f("AugSrc", AugSrc);
// printMat4x4f("MatModel", pMatModel);
// printMat4x4f("MatProj", pMatProj);
// MatrixMultiply4x4_SSE(pMatModel, pMatProj, mvp);
// Mat4x1Transform_SSE(mvp, AugSrc, dst);
// print4f("dst", dst);
}
/*
void TransformModelToClip_SSE2( const float x[3], const float pMatModel[16], const float pMatProj[16], float dst[4] )
{
// 7/8 broadcaster, 8 load, 7/8 mult, 6 add
__m128 row = _mm_add_ps(
_mm_add_ps( _mm_mul_ps( _mm_set1_ps(x[0]), _mm_load_ps(pMatModel ) ) ,
_mm_mul_ps( _mm_set1_ps(x[1]), _mm_load_ps(pMatModel+4 ) ) )
,
_mm_add_ps( _mm_mul_ps( _mm_set1_ps(x[2]), _mm_load_ps(pMatModel+8 ) ) ,
_mm_load_ps(pMatModel+12) ) );
_mm_store_ps(dst, _mm_add_ps(
_mm_add_ps( _mm_mul_ps( _mm_set1_ps(row[0]), _mm_load_ps(pMatProj ) ) ,
_mm_mul_ps( _mm_set1_ps(row[1]), _mm_load_ps(pMatProj+4 ) ) )
,
_mm_add_ps( _mm_mul_ps( _mm_set1_ps(row[2]), _mm_load_ps(pMatProj+8 ) ) ,
_mm_mul_ps( _mm_set1_ps(row[3]), _mm_load_ps(pMatProj+12) ) ) )
);
// _mm_store_ps(dst, row);
// Mat4x1Transform_SSE(pMatModel, AugSrc, eye);
// Mat4x1Transform_SSE(pMatProj, eye, dst);
}
*/
// ===============================================
// not used now
// ===============================================
/*
void Mat4SimpleInverse( const float in[16], float out[16])
{
float v[3];
float invSqrLen;
VectorCopy(in + 0, v);
invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
out[ 0] = v[0]; out[ 4] = v[1]; out[ 8] = v[2]; out[12] = -DotProduct(v, &in[12]);
VectorCopy(in + 4, v);
invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
out[ 1] = v[0]; out[ 5] = v[1]; out[ 9] = v[2]; out[13] = -DotProduct(v, &in[12]);
VectorCopy(in + 8, v);
invSqrLen = 1.0f / DotProduct(v, v); VectorScale(v, invSqrLen, v);
out[ 2] = v[0]; out[ 6] = v[1]; out[10] = v[2]; out[14] = -DotProduct(v, &in[12]);
out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f;
}
void Mat4Dump( const float in[16] )
{
printf( "%3.5f %3.5f %3.5f %3.5f\n", in[ 0], in[ 4], in[ 8], in[12]);
printf( "%3.5f %3.5f %3.5f %3.5f\n", in[ 1], in[ 5], in[ 9], in[13]);
printf( "%3.5f %3.5f %3.5f %3.5f\n", in[ 2], in[ 6], in[10], in[14]);
printf( "%3.5f %3.5f %3.5f %3.5f\n", in[ 3], in[ 7], in[11], in[15]);
}
void Mat4View(vec3_t axes[3], vec3_t origin, mat4_t out)
{
out[0] = axes[0][0];
out[1] = axes[1][0];
out[2] = axes[2][0];
out[3] = 0;
out[4] = axes[0][1];
out[5] = axes[1][1];
out[6] = axes[2][1];
out[7] = 0;
out[8] = axes[0][2];
out[9] = axes[1][2];
out[10] = axes[2][2];
out[11] = 0;
out[12] = -DotProduct(origin, axes[0]);
out[13] = -DotProduct(origin, axes[1]);
out[14] = -DotProduct(origin, axes[2]);
out[15] = 1;
}
*/

View file

@ -0,0 +1,24 @@
#ifndef MATRIX_MULTIPLICATION_H_
#define MATRIX_MULTIPLICATION_H_
void Mat4Copy( const float in[64], float out[16] );
void Mat3x3Copy( float dst[3][3], const float src[3][3] );
void VectorLerp( float a[3], float b[3], float lerp, float out[3]);
void VectorNorm( float v[3] );
float VectorLen( const float v[3] );
void TransformModelToClip( const float src[3], const float *modelMatrix, const float *projectionMatrix, float eye[4], float dst[4] );
void TransformModelToClip_SSE( const float src[3], const float pMatModel[16], const float pMatProj[16], float dst[4] );
void Mat4Identity( float out[4] );
void MatrixMultiply4x4_SSE(const float A[16], const float B[16], float out[16]);
void Mat4x1Transform_SSE( const float A[16], const float x[4], float out[4] );
void Mat4Transform( const float in1[16], const float in2[4], float out[4] );
void Mat4Translation( float vec[3], float out[4] );
void Mat3x3Identity( float pMat[3][3] );
void VectorPerp( const vec3_t src, vec3_t dst );
float MakeTwoPerpVectors(const float forward[3], float right[3], float up[3]);
void Vec3Transform(const float Mat[16], const float v[3], float out[3]);
#endif

View file

@ -0,0 +1,158 @@
#include "../qcommon/q_shared.h"
#include "../renderercommon/tr_public.h"
extern refexport_t* R_Export(void);
refimport_t ri;
/*
@@@@@@@@@@@@@@@@@@@@@
GetRefAPI
@@@@@@@@@@@@@@@@@@@@@
*/
#ifdef USE_RENDERER_DLOPEN
Q_EXPORT refexport_t* QDECL GetRefAPI( int apiVersion, refimport_t *rimp )
{
#else
refexport_t* GetRefAPI(int apiVersion, refimport_t *rimp)
{
#endif
ri = *rimp;
if( apiVersion != REF_API_VERSION )
{
ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n", REF_API_VERSION, apiVersion );
return NULL;
}
return R_Export();
}
//
// common function replacements for modular renderer
//
#ifdef USE_RENDERER_DLOPEN
void QDECL Com_Printf( const char *msg, ... )
{
va_list argptr;
char text[1024];
va_start(argptr, msg);
Q_vsnprintf(text, sizeof(text), msg, argptr);
va_end(argptr);
ri.Printf(PRINT_ALL, "%s", text);
}
void QDECL Com_Error( int level, const char *error, ... )
{
va_list argptr;
char text[1024];
va_start(argptr, error);
Q_vsnprintf(text, sizeof(text), error, argptr);
va_end(argptr);
ri.Error(level, "%s", text);
}
#endif
// =======================================
// =======================================
// =======================================
char* R_SkipPath (char *pathname)
{
char* last = pathname;
while (*pathname)
{
if (*pathname=='/')
last = pathname+1;
pathname++;
}
return last;
}
/*
char* SkipPath(char *pathname)
{
char* last = pathname;
char c;
do{
c = *pathname;
if (c == '/')
last = pathname+1;
pathname++;
}while(c);
return last;
}
*/
void R_StripExtension( const char *in, char *out, int destsize )
{
const char *dot = strrchr(in, '.'), *slash;
if (dot && (!(slash = strrchr(in, '/')) || slash < dot))
destsize = (destsize < dot-in+1 ? destsize : dot-in+1);
if ( in == out && destsize > 1 )
out[destsize-1] = '\0';
else
Q_strncpyz(out, in, destsize);
}
/*
void stripExtension(const char *in, char *out, int destsize)
{
const char *dot = strrchr(in, '.');
const char *slash = strrchr(in, '/');
if ((dot != NULL) && ( (slash == NULL) || (slash < dot) ) )
{
int len = dot-in+1;
if(len <= destsize)
destsize = len;
else
ri.Printf( PRINT_WARNING, "stripExtension: dest size not enough!\n");
}
if(in != out)
strncpy(out, in, destsize-1);
out[destsize-1] = '\0';
}
const char *R_GetExtension( const char *name )
{
const char *dot = strrchr(name, '.'), *slash;
if (dot && (!(slash = strrchr(name, '/')) || slash < dot))
return dot + 1;
else
return "";
}
*/
/*
char* GetExtension( const char *name )
{
char* dot = strrchr(name, '.');
char* slash = strrchr(name, '/');
if ((dot != NULL) && ((slash == NULL) || (slash < dot) ))
return dot + 1;
else
return "";
}
*/

View file

@ -0,0 +1,13 @@
#ifndef REF_IMPORT_H_
#define REF_IMPORT_H_
#include "../qcommon/q_shared.h"
#include "../renderercommon/tr_public.h"
extern refimport_t ri;
char* R_SkipPath (char *pathname);
void R_StripExtension( const char *in, char *out, int destsize );
// const char* R_GetExtension( const char *name );
#endif

View file

@ -0,0 +1,65 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "render_export.h"
refexport_t* R_Export(void)
{
static refexport_t re;
// memset(&re, 0, sizeof(re));
// the RE_ functions are Renderer Entry points
re.Shutdown = RE_Shutdown;
re.BeginRegistration = RE_BeginRegistration;
re.RegisterModel = RE_RegisterModel;
re.RegisterSkin = RE_RegisterSkin;
re.RegisterShader = RE_RegisterShader;
re.RegisterShaderNoMip = RE_RegisterShaderNoMip;
re.LoadWorld = RE_LoadWorldMap;
re.SetWorldVisData = RE_SetWorldVisData;
re.EndRegistration = RE_EndRegistration;
re.ClearScene = RE_ClearScene;
re.AddRefEntityToScene = RE_AddRefEntityToScene;
re.AddPolyToScene = RE_AddPolyToScene;
re.LightForPoint = RE_LightForPoint;
re.AddLightToScene = RE_AddLightToScene;
re.AddAdditiveLightToScene = RE_AddAdditiveLightToScene;
re.RenderScene = RE_RenderScene;
re.SetColor = RE_SetColor;
re.DrawStretchPic = RE_StretchPic;
re.DrawStretchRaw = RE_StretchRaw;
re.UploadCinematic = RE_UploadCinematic;
re.BeginFrame = RE_BeginFrame;
re.EndFrame = RE_EndFrame;
re.MarkFragments = RE_MarkFragments;
re.LerpTag = RE_LerpTag;
re.ModelBounds = RE_ModelBounds;
re.RegisterFont = RE_RegisterFont;
re.RemapShader = RE_RemapShader;
re.GetEntityToken = RE_GetEntityToken;
re.inPVS = RE_inPVS;
re.TakeVideoFrame = RE_TakeVideoFrame;
return &re;
}

View file

@ -0,0 +1,57 @@
#ifndef RENDER_EXPORT_H_
#define RENDER_EXPORT_H_
#include "../qcommon/q_shared.h"
#include "../renderercommon/tr_types.h"
#include "../renderercommon/tr_public.h"
// Total 30 exported function
void RE_Shutdown( qboolean destroyWindow );
void RE_BeginRegistration( glconfig_t *glconfig );
qhandle_t RE_RegisterModel( const char *name );
qhandle_t RE_RegisterSkin( const char *name );
qhandle_t RE_RegisterShader( const char *name );
qhandle_t RE_RegisterShaderNoMip( const char *name );
void RE_LoadWorldMap( const char *mapname );
void RE_SetWorldVisData( const byte *vis );
void RE_EndRegistration( void );
void RE_ClearScene( void );
void RE_AddRefEntityToScene( const refEntity_t *ent );
void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num );
int RE_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b );
void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b );
void RE_RenderScene( const refdef_t *fd );
void RE_SetColor( const float *rgba );
void RE_StretchPic ( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const unsigned char *data, int client, qboolean dirty);
void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty);
void RE_BeginFrame( stereoFrame_t stereoFrame );
void RE_EndFrame( int *frontEndMsec, int *backEndMsec );
// MARKERS, POLYGON PROJECTION ON WORLD POLYGONS
int RE_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer );
int RE_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
float frac, const char *tagName );
void RE_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs );
void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
void RE_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset);
qboolean RE_GetEntityToken( char *buffer, int size );
qboolean RE_inPVS( const vec3_t p1, const vec3_t p2 );
void RE_TakeVideoFrame( int width, int height, unsigned char *captureBuffer, unsigned char *encodeBuffer, qboolean motionJpeg );
#endif

1
code/renderervk/shaders/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
bintoc

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,208 @@
unsigned char multi_texture_clipping_plane_vert_spv[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00,
0x08, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00,
0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73,
0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00,
0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x0F, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x43, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00,
0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00,
0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0C, 0x00,
0x00, 0x00, 0x69, 0x6E, 0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74,
0x69, 0x6F, 0x6E, 0x00, 0x05, 0x00, 0x06, 0x00, 0x16, 0x00,
0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65,
0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
0x06, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
0x6E, 0x00, 0x06, 0x00, 0x07, 0x00, 0x16, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69,
0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x00,
0x05, 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x54, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x6F, 0x72, 0x6D, 0x00,
0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x73,
0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1D, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x79, 0x65, 0x5F,
0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72,
0x6D, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x70, 0x69,
0x6E, 0x67, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0x00,
0x05, 0x00, 0x03, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00,
0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72,
0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x3A, 0x00, 0x00, 0x00,
0x69, 0x6E, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x3E, 0x00, 0x00, 0x00,
0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63,
0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, 0x05, 0x00, 0x06, 0x00,
0x40, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78,
0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, 0x00, 0x00,
0x05, 0x00, 0x06, 0x00, 0x42, 0x00, 0x00, 0x00, 0x66, 0x72,
0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F,
0x72, 0x64, 0x31, 0x00, 0x05, 0x00, 0x06, 0x00, 0x43, 0x00,
0x00, 0x00, 0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63,
0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x16, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x16, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x16, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00,
0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00,
0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x48, 0x00,
0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00,
0x05, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x47, 0x00,
0x03, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x42, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x43, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00,
0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x3F, 0x15, 0x00, 0x04, 0x00, 0x13, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00,
0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x17, 0x00,
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x15, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x19, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00,
0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00, 0x1D, 0x00,
0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x20, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1B, 0x00,
0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2B, 0x00,
0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x19, 0x00,
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x09, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x2D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1C, 0x00,
0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x36, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x39, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3A, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3F, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x3D, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x43, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00,
0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x51, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00,
0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00,
0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x1F, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x24, 0x00,
0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00,
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x24, 0x00,
0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2D, 0x00,
0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,
0x27, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00,
0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x90, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x30, 0x00,
0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00,
0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x94, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x41, 0x00,
0x06, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x37, 0x00, 0x00, 0x00,
0x35, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x03, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x44, 0x00,
0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0xFD, 0x00,
0x01, 0x00, 0x38, 0x00, 0x01, 0x00, };
int multi_texture_clipping_plane_vert_spv_size = 2056;

View file

@ -0,0 +1,263 @@
unsigned char multi_texture_frag_spv[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00,
0x08, 0x00, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00,
0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C,
0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0A, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1B, 0x00,
0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00,
0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x08, 0x00,
0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61,
0x6E, 0x65, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0F, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6C, 0x69,
0x70, 0x5F, 0x64, 0x69, 0x73, 0x74, 0x00, 0x00, 0x05, 0x00,
0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6C, 0x6F,
0x72, 0x5F, 0x61, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1B, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C,
0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x20, 0x00,
0x00, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x30,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x24, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78,
0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, 0x05, 0x00,
0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6C, 0x6F,
0x72, 0x5F, 0x62, 0x00, 0x05, 0x00, 0x05, 0x00, 0x29, 0x00,
0x00, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x31,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x2B, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78,
0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, 0x05, 0x00,
0x05, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6C, 0x6F,
0x72, 0x5F, 0x6F, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
0x05, 0x00, 0x33, 0x00, 0x00, 0x00, 0x6F, 0x75, 0x74, 0x5F,
0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00,
0x06, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x61, 0x6C, 0x70, 0x68,
0x61, 0x5F, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x66, 0x75, 0x6E,
0x63, 0x00, 0x47, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1B, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x22, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x29, 0x00,
0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x33, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00,
0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x06, 0x00,
0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x34, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0A, 0x00,
0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00,
0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x17, 0x00,
0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00,
0x09, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1F, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00,
0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x23, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x1F, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, 0x06, 0x00,
0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00,
0x2E, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x32, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x32, 0x00,
0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x3A, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4B, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00,
0x06, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0xAA, 0x00,
0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x34, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00,
0x58, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x4A, 0x00,
0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3F, 0x2B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x63, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, 0x00,
0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
0xAA, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x63, 0x00,
0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x0A, 0x00,
0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x00, 0x06, 0x00,
0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x0C, 0x00,
0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x0C, 0x00, 0x00, 0x00,
0xF5, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x13, 0x00,
0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF7, 0x00,
0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFA, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00,
0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x14, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x17, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1B, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x17, 0x00,
0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x25, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x17, 0x00,
0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x26, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x19, 0x00,
0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x29, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x57, 0x00,
0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x03, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
0xF7, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x17, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x19, 0x00,
0x00, 0x00, 0x4F, 0x00, 0x08, 0x00, 0x34, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x35, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x17, 0x00,
0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x4F, 0x00, 0x08, 0x00, 0x34, 0x00, 0x00, 0x00, 0x38, 0x00,
0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x34, 0x00, 0x00, 0x00,
0x39, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00,
0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x41, 0x00,
0x05, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x3F, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x17, 0x00,
0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00,
0x45, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x31, 0x00,
0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x47, 0x00,
0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x17, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00,
0x49, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00,
0x49, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x31, 0x00,
0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x31, 0x00, 0x00, 0x00,
0xF7, 0x00, 0x03, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x4C, 0x00, 0x00, 0x00,
0x4D, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x4F, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x33, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x50, 0x00,
0x00, 0x00, 0xB4, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x11, 0x00,
0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x52, 0x00,
0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x53, 0x00, 0x00, 0x00, 0xFC, 0x00,
0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x54, 0x00, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x4E, 0x00, 0x00, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x56, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00,
0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00,
0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
0x62, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x59, 0x00,
0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x4F, 0x00, 0x00, 0x00,
0x5B, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x5C, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0xBE, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x00,
0x5C, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00, 0xF7, 0x00,
0x03, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFA, 0x00, 0x04, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x5F, 0x00,
0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x5F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x60, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x5A, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x62, 0x00,
0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x66, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x64, 0x00,
0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 0x41, 0x00,
0x05, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
0x67, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x00, 0x06, 0x00,
0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
0x5D, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x6B, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00,
0x69, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x6B, 0x00,
0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x6A, 0x00, 0x00, 0x00,
0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x6B, 0x00,
0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x66, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x66, 0x00, 0x00, 0x00, 0xF9, 0x00,
0x02, 0x00, 0x5A, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x5A, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x4E, 0x00,
0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x4E, 0x00, 0x00, 0x00,
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, };
int multi_texture_frag_spv_size = 2608;

View file

@ -0,0 +1,215 @@
unsigned char multi_texture_vert_spv[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00,
0x08, 0x00, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00,
0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C,
0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x15, 0x00,
0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x42, 0x00,
0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01,
0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x69, 0x6E,
0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00,
0x05, 0x00, 0x06, 0x00, 0x13, 0x00, 0x00, 0x00, 0x67, 0x6C,
0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x13, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50,
0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x05, 0x00,
0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x54, 0x72,
0x61, 0x6E, 0x73, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x00, 0x00,
0x06, 0x00, 0x08, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x73, 0x70, 0x61,
0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, 0x00, 0x00,
0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x65, 0x79, 0x65, 0x5F, 0x73, 0x70,
0x61, 0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D, 0x00,
0x06, 0x00, 0x07, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x70, 0x69, 0x6E, 0x67,
0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0x00, 0x05, 0x00,
0x03, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00, 0x63, 0x6C,
0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0x00,
0x05, 0x00, 0x06, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x66, 0x72,
0x61, 0x67, 0x5F, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x64, 0x69,
0x73, 0x74, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x3A, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C,
0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x3C, 0x00,
0x00, 0x00, 0x69, 0x6E, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x40, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78,
0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00, 0x05, 0x00,
0x06, 0x00, 0x42, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x74,
0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x30, 0x00,
0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x44, 0x00, 0x00, 0x00,
0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63,
0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, 0x05, 0x00, 0x06, 0x00,
0x45, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78,
0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x31, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00,
0x04, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
0x47, 0x00, 0x03, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x3A, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x40, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x44, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x45, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00,
0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0A, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x1E, 0x00,
0x03, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00,
0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x18, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x18, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x22, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x32, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x24, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00,
0x25, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, 0x25, 0x00,
0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x29, 0x00,
0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2B, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x31, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x22, 0x00,
0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x3B, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x3F, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x44, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x04, 0x00, 0x41, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00,
0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00,
0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00,
0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0E, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1D, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x18, 0x00,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00,
0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x15, 0x00,
0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x23, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xF7, 0x00,
0x03, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFA, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00,
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x27, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2C, 0x00,
0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2F, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x1C, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x19, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x32, 0x00,
0x00, 0x00, 0x90, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x33, 0x00,
0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x37, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00,
0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x00,
0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x39, 0x00,
0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x28, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x3A, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x3E, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x42, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00,
0x43, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3E, 0x00,
0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x44, 0x00, 0x00, 0x00, 0x46, 0x00,
0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
int multi_texture_vert_spv_size = 2120;

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,193 @@
unsigned char single_texture_clipping_plane_vert_spv[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00,
0x08, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00,
0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73,
0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00,
0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x0F, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x05, 0x00,
0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00,
0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x70, 0x6F, 0x73,
0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x05, 0x00, 0x06, 0x00,
0x16, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72,
0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x06, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74,
0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00, 0x16, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x43,
0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63,
0x65, 0x00, 0x05, 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1D, 0x00,
0x00, 0x00, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x6F, 0x72,
0x6D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x1D, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70,
0x5F, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F,
0x72, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x79,
0x65, 0x5F, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, 0x66,
0x6F, 0x72, 0x6D, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1D, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70,
0x70, 0x69, 0x6E, 0x67, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65,
0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x38, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C,
0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x3A, 0x00,
0x00, 0x00, 0x69, 0x6E, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x3E, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78,
0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x05, 0x00,
0x06, 0x00, 0x40, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x74,
0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00,
0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00,
0x05, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00,
0x05, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00,
0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x48, 0x00, 0x04, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00,
0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x70, 0x00,
0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x38, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x3E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00,
0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00,
0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0B, 0x00,
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x15, 0x00, 0x04, 0x00,
0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00,
0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x04, 0x00, 0x16, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00,
0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x1B, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x18, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x05, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1D, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x1F, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x27, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00,
0x19, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x36, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x38, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x39, 0x00, 0x00, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00,
0x04, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3D, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x3F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3C, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00,
0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x51, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00,
0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00,
0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x1F, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x24, 0x00,
0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00,
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x24, 0x00,
0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00,
0x2A, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2D, 0x00,
0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,
0x27, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00,
0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x90, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x30, 0x00,
0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00,
0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x94, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x41, 0x00,
0x06, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x37, 0x00, 0x00, 0x00,
0x35, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x38, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x03, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, };
int single_texture_clipping_plane_vert_spv_size = 1908;

View file

@ -0,0 +1,181 @@
unsigned char single_texture_frag_spv[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00,
0x08, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00,
0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C,
0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x09, 0x00, 0x04, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x19, 0x00,
0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00,
0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x63, 0x6C,
0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0x00,
0x05, 0x00, 0x06, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x66, 0x72,
0x61, 0x67, 0x5F, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x64, 0x69,
0x73, 0x74, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x19, 0x00,
0x00, 0x00, 0x6F, 0x75, 0x74, 0x5F, 0x63, 0x6F, 0x6C, 0x6F,
0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1B, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C,
0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x20, 0x00,
0x00, 0x00, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x30,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x24, 0x00,
0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74, 0x65, 0x78,
0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x05, 0x00,
0x06, 0x00, 0x28, 0x00, 0x00, 0x00, 0x61, 0x6C, 0x70, 0x68,
0x61, 0x5F, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x66, 0x75, 0x6E,
0x63, 0x00, 0x47, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x19, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x28, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00,
0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x14, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00,
0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xAB, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x16, 0x00, 0x03, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x19, 0x00, 0x09, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x03, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1F, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x17, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x34, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2A, 0x00,
0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x2D, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2E, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x2F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
0x37, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00,
0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0xAA, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x37, 0x00,
0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x2B, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00, 0x06, 0x00,
0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x36, 0x00,
0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00,
0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x0B, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xB8, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0xF9, 0x00,
0x02, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x0C, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x07, 0x00, 0x06, 0x00,
0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0B, 0x00,
0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x13, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0xFC, 0x00,
0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x15, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1C, 0x00,
0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00,
0x25, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x57, 0x00,
0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00,
0x21, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x85, 0x00,
0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x03, 0x00, 0x19, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0xF7, 0x00, 0x03, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x2F, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x19, 0x00,
0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x30, 0x00,
0x00, 0x00, 0xB4, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x32, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x11, 0x00,
0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x34, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x32, 0x00,
0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00, 0xFC, 0x00,
0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x2C, 0x00, 0x00, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x36, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00,
0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x39, 0x00,
0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x2E, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0xBE, 0x00,
0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xF7, 0x00,
0x03, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFA, 0x00, 0x04, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3F, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x3F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00,
0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x3A, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x42, 0x00,
0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x46, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x44, 0x00,
0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00,
0x05, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x00, 0x06, 0x00,
0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x4B, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00,
0x49, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x4B, 0x00,
0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x4A, 0x00, 0x00, 0x00,
0xFC, 0x00, 0x01, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x4B, 0x00,
0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00, 0xF9, 0x00,
0x02, 0x00, 0x3A, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x3A, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x2C, 0x00,
0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x2C, 0x00, 0x00, 0x00,
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, };
int single_texture_frag_spv_size = 1788;

View file

@ -0,0 +1,200 @@
unsigned char single_texture_vert_spv[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0B, 0x00,
0x08, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00,
0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C,
0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x15, 0x00,
0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x42, 0x00,
0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
0xC2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00,
0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x70, 0x00,
0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x69, 0x6E, 0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
0x6E, 0x00, 0x05, 0x00, 0x06, 0x00, 0x13, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74,
0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00,
0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C,
0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00,
0x05, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x54, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x6F, 0x72, 0x6D, 0x00,
0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x5F, 0x73,
0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72, 0x6D,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x79, 0x65, 0x5F,
0x73, 0x70, 0x61, 0x63, 0x65, 0x5F, 0x78, 0x66, 0x6F, 0x72,
0x6D, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x63, 0x6C, 0x69, 0x70, 0x70, 0x69,
0x6E, 0x67, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x00, 0x00,
0x05, 0x00, 0x03, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00,
0x63, 0x6C, 0x69, 0x70, 0x5F, 0x70, 0x6C, 0x61, 0x6E, 0x65,
0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6C, 0x69, 0x70, 0x5F,
0x64, 0x69, 0x73, 0x74, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x3A, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63,
0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x5F, 0x63, 0x6F, 0x6C,
0x6F, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00,
0x40, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x74,
0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00,
0x05, 0x00, 0x06, 0x00, 0x42, 0x00, 0x00, 0x00, 0x69, 0x6E,
0x5F, 0x74, 0x65, 0x78, 0x5F, 0x63, 0x6F, 0x6F, 0x72, 0x64,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0C, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00,
0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00,
0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00,
0x04, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x70, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x1A, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00,
0x04, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x3C, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x42, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00,
0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F,
0x1E, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x16, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00,
0x18, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1E, 0x00,
0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x19, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x1A, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x1B, 0x00,
0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x09, 0x00,
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x22, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
0x02, 0x00, 0x25, 0x00, 0x00, 0x00, 0x34, 0x00, 0x06, 0x00,
0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xAB, 0x00,
0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x29, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00,
0x04, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x16, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00, 0x09, 0x00,
0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x22, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x04, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x3E, 0x00,
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x3F, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3B, 0x00,
0x04, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00,
0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00,
0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00,
0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0E, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1D, 0x00,
0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x18, 0x00,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00,
0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x15, 0x00,
0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x23, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xF7, 0x00,
0x03, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFA, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00,
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x27, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2C, 0x00,
0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00,
0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2F, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x1C, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x19, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x32, 0x00,
0x00, 0x00, 0x90, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x33, 0x00,
0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
0x37, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00,
0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x00,
0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x39, 0x00,
0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0x28, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x3A, 0x00,
0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x3E, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x42, 0x00,
0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00,
0x43, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00,
0x01, 0x00, };
int single_texture_vert_spv_size = 1972;

View file

@ -0,0 +1,26 @@
#include <stdio.h>
#include <assert.h>
int main(int argc, char** argv) {
if(argc != 3)
return 0;
char* fn = argv[1];
FILE* f = fopen(fn, "rb");
printf("unsigned char %s[] = {\n", argv[2]);
unsigned long n = 0;
while(!feof(f)) {
unsigned char c;
if(fread(&c, 1, 1, f) == 0) break;
printf("0x%.2X, ", (int)c);
++n;
if(n % 10 == 0) printf("\n");
}
fclose(f);
printf("};\n");
printf("int %s_size = %ld;\n", argv[2], n);
return 0;
}

View file

@ -0,0 +1,25 @@
@echo off
set "VSCMD_START_DIR=%CD%"
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"
set tools_dir=..\..\..\..\tools
set bin2hex=%tools_dir%\bin2hex.exe
set bin2hex_cpp=%tools_dir%\bin2hex.cpp
if not exist %bin2hex% (
cl.exe /EHsc /nologo /Fe%tools_dir%\ /Fo%tools_dir%\ %bin2hex_cpp%
)
set PATH=%tools_dir%;%PATH%
for %%f in (*.vert) do (
%VULKAN_SDK%\Bin\glslangValidator.exe -V %%f
%bin2hex% vert.spv %%~nf_vert_spv > spirv/%%~nf_vert.cpp
del vert.spv
)
for %%f in (*.frag) do (
%VULKAN_SDK%\Bin\glslangValidator.exe -V %%f
%bin2hex% frag.spv %%~nf_frag_spv > spirv/%%~nf_frag.cpp
del frag.spv
)

View file

@ -0,0 +1,20 @@
#!/bin/bash
if [[ ! -x "./bintoc" ]]
then
gcc bintoc.c -o bintoc
fi
find -type f -name "*.vert" | \
while read f; do glslangValidator -V ${f} -o "Compiled/${f%.*}.vspv"; done
find -type f -name "*.frag" | \
while read f; do glslangValidator -V ${f} -o "Compiled/${f%.*}.fspv"; done
find -type f -name "*.vspv" | \
while read f; do ./bintoc ${f} `basename ${f%.*}`_vert_spv > ${f%.*}_vert.c; done
find -type f -name "*.fspv" | \
while read f; do ./bintoc ${f} `basename ${f%.*}`_frag_spv > ${f%.*}_frag.c; done

View file

@ -0,0 +1,82 @@
@echo off
set "VSCMD_START_DIR=%CD%"
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"
set tools_dir=..\..\..\..\tools
set bin2hex=%tools_dir%\bin2hex.exe
set bin2hex_cpp=%tools_dir%\bin2hex.cpp
if not exist %bin2hex% (
cl.exe /EHsc /nologo /Fe%tools_dir%\ /Fo%tools_dir%\ %bin2hex_cpp%
)
set PATH=%tools_dir%;%PATH%
@rem single texture VS
fxc.exe /nologo /T vs_4_0 /E single_texture_vs /Fo shader.bin shaders.hlsl
%bin2hex% shader.bin single_texture_vs > hlsl_compiled/single_texture_vs.cpp
del shader.bin
fxc.exe /nologo /T vs_4_0 /E single_texture_clipping_plane_vs /Fo shader.bin shaders.hlsl
%bin2hex% shader.bin single_texture_clipping_plane_vs > hlsl_compiled/single_texture_clipping_plane_vs.cpp
del shader.bin
@rem multi texture VS
fxc.exe /nologo /T vs_4_0 /E multi_texture_vs /Fo shader.bin shaders.hlsl
%bin2hex% shader.bin multi_texture_vs > hlsl_compiled/multi_texture_vs.cpp
del shader.bin
fxc.exe /nologo /T vs_4_0 /E multi_texture_clipping_plane_vs /Fo shader.bin shaders.hlsl
%bin2hex% shader.bin multi_texture_clipping_plane_vs > hlsl_compiled/multi_texture_clipping_plane_vs.cpp
del shader.bin
@rem signle texture PS
fxc.exe /nologo /T ps_4_0 /E single_texture_ps /Fo shader.bin shaders.hlsl
%bin2hex% shader.bin single_texture_ps > hlsl_compiled/single_texture_ps.cpp
del shader.bin
fxc.exe /nologo /T ps_4_0 /E single_texture_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GT0
%bin2hex% shader.bin single_texture_gt0_ps > hlsl_compiled/single_texture_gt0_ps.cpp
del shader.bin
fxc.exe /nologo /T ps_4_0 /E single_texture_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_LT80
%bin2hex% shader.bin single_texture_lt80_ps > hlsl_compiled/single_texture_lt80_ps.cpp
del shader.bin
fxc.exe /nologo /T ps_4_0 /E single_texture_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GE80
%bin2hex% shader.bin single_texture_ge80_ps > hlsl_compiled/single_texture_ge80_ps.cpp
del shader.bin
@rem multi texture mul PS
fxc.exe /nologo /T ps_4_0 /E multi_texture_mul_ps /Fo shader.bin shaders.hlsl
%bin2hex% shader.bin multi_texture_mul_ps > hlsl_compiled/multi_texture_mul_ps.cpp
del shader.bin
fxc.exe /nologo /T ps_4_0 /E multi_texture_mul_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GT0
%bin2hex% shader.bin multi_texture_mul_gt0_ps > hlsl_compiled/multi_texture_mul_gt0_ps.cpp
del shader.bin
fxc.exe /nologo /T ps_4_0 /E multi_texture_mul_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_LT80
%bin2hex% shader.bin multi_texture_mul_lt80_ps > hlsl_compiled/multi_texture_mul_lt80_ps.cpp
del shader.bin
fxc.exe /nologo /T ps_4_0 /E multi_texture_mul_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GE80
%bin2hex% shader.bin multi_texture_mul_ge80_ps > hlsl_compiled/multi_texture_mul_ge80_ps.cpp
del shader.bin
@rem multi texture add PS
fxc.exe /nologo /T ps_4_0 /E multi_texture_add_ps /Fo shader.bin shaders.hlsl
%bin2hex% shader.bin multi_texture_add_ps > hlsl_compiled/multi_texture_add_ps.cpp
del shader.bin
fxc.exe /nologo /T ps_4_0 /E multi_texture_add_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GT0
%bin2hex% shader.bin multi_texture_add_gt0_ps > hlsl_compiled/multi_texture_add_gt0_ps.cpp
del shader.bin
fxc.exe /nologo /T ps_4_0 /E multi_texture_add_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_LT80
%bin2hex% shader.bin multi_texture_add_lt80_ps > hlsl_compiled/multi_texture_add_lt80_ps.cpp
del shader.bin
fxc.exe /nologo /T ps_4_0 /E multi_texture_add_ps /Fo shader.bin shaders.hlsl /DALPHA_TEST_GE80
%bin2hex% shader.bin multi_texture_add_ge80_ps > hlsl_compiled/multi_texture_add_ge80_ps.cpp
del shader.bin

View file

@ -0,0 +1,36 @@
#version 450
layout(set = 0, binding = 0) uniform sampler2D texture0;
layout(set = 1, binding = 0) uniform sampler2D texture1;
layout(location = 0) in vec4 frag_color;
layout(location = 1) in vec2 frag_tex_coord0;
layout(location = 2) in vec2 frag_tex_coord1;
layout(location = 3) in float frag_clip_dist;
layout(location = 0) out vec4 out_color;
layout (constant_id = 0) const int alpha_test_func = 0;
layout (constant_id = 1) const int color_op = 0;
layout (constant_id = 2) const int clip_plane = 0;
void main() {
if (clip_plane != 0 && frag_clip_dist < 0.0) discard;
vec4 color_a = frag_color * texture(texture0, frag_tex_coord0);
vec4 color_b = texture(texture1, frag_tex_coord1);
if (color_op != 0)
out_color = vec4(color_a.rgb + color_b.rgb, color_a.a * color_b.a);
else {
out_color = color_a * color_b;
}
if (alpha_test_func == 1) {
if (out_color.a == 0.0f) discard;
} else if (alpha_test_func == 2) {
if (out_color.a >= 0.5f) discard;
} else if (alpha_test_func == 3) {
if (out_color.a < 0.5f) discard;
}
}

View file

@ -0,0 +1,37 @@
#version 450
// 128 bytes
layout(push_constant) uniform Transform {
mat4x4 clip_space_xform;
// a single-precision floating-point matrix with 3 columns and 4 rows
mat3x4 eye_space_xform;
vec4 clipping_plane; // in eye space
};
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec4 in_color;
layout(location = 2) in vec2 in_tex_coord0;
layout(location = 3) in vec2 in_tex_coord1;
layout(location = 0) out vec4 frag_color;
layout(location = 1) out vec2 frag_tex_coord0;
layout(location = 2) out vec2 frag_tex_coord1;
layout(location = 3) out float frag_clip_dist;
layout (constant_id = 2) const int clip_plane = 0;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
vec4 p = vec4(in_position, 1.0);
gl_Position = clip_space_xform * p;
if (clip_plane != 0)
frag_clip_dist = dot(clipping_plane, vec4( p * eye_space_xform, 1.0));
frag_color = in_color;
frag_tex_coord0 = in_tex_coord0;
frag_tex_coord1 = in_tex_coord1;
}

View file

@ -0,0 +1,34 @@
#version 450
// 128 bytes
layout(push_constant) uniform Transform {
mat4x4 clip_space_xform;
// a single-precision floating-point matrix with 3 columns and 4 rows
mat3x4 eye_space_xform;
vec4 clipping_plane; // in eye space
};
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec4 in_color;
layout(location = 2) in vec2 in_tex_coord0;
layout(location = 3) in vec2 in_tex_coord1;
layout(location = 0) out vec4 frag_color;
layout(location = 1) out vec2 frag_tex_coord0;
layout(location = 2) out vec2 frag_tex_coord1;
out gl_PerVertex {
vec4 gl_Position;
float gl_ClipDistance[1];
};
void main() {
vec4 p = vec4(in_position, 1.0);
gl_Position = clip_space_xform * p;
gl_ClipDistance[0] = dot(clipping_plane, vec4( p * eye_space_xform, 1.0));
frag_color = in_color;
frag_tex_coord0 = in_tex_coord0;
frag_tex_coord1 = in_tex_coord1;
}

View file

@ -0,0 +1,131 @@
struct Single_Texture_PS_Data {
float4 position : SV_POSITION;
float4 color : COLOR;
float2 uv0 : TEXCOORD;
};
struct Multi_Texture_PS_Data {
float4 position : SV_POSITION;
float4 color : COLOR;
float2 uv0 : TEXCOORD0;
float2 uv1 : TEXCOORD1;
};
cbuffer Constants : register(b0) {
float4x4 clip_space_xform;
float4x3 eye_space_xform;
float4 clipping_plane; // in eye space
};
Texture2D texture0 : register(t0);
SamplerState sampler0 : register(s0);
Texture2D texture1 : register(t1);
SamplerState sampler1 : register(s1);
Single_Texture_PS_Data single_texture_vs(
float4 position : POSITION,
float4 color : COLOR,
float2 uv0 : TEXCOORD)
{
Single_Texture_PS_Data ps_data;
ps_data.position = mul(clip_space_xform, position);
ps_data.color = color;
ps_data.uv0 = uv0;
return ps_data;
}
Single_Texture_PS_Data single_texture_clipping_plane_vs(
float4 position : POSITION,
float4 color : COLOR,
float2 uv0 : TEXCOORD,
out float clip : SV_ClipDistance)
{
clip = dot(clipping_plane.xyz, mul(position, eye_space_xform)) + clipping_plane.w;
Single_Texture_PS_Data ps_data;
ps_data.position = mul(clip_space_xform, position);
ps_data.color = color;
ps_data.uv0 = uv0;
return ps_data;
}
Multi_Texture_PS_Data multi_texture_vs(
float4 position : POSITION,
float4 color : COLOR,
float2 uv0 : TEXCOORD0,
float2 uv1 : TEXCOORD1)
{
Multi_Texture_PS_Data ps_data;
ps_data.position = mul(clip_space_xform, position);
ps_data.color = color;
ps_data.uv0 = uv0;
ps_data.uv1 = uv1;
return ps_data;
}
Multi_Texture_PS_Data multi_texture_clipping_plane_vs(
float4 position : POSITION,
float4 color : COLOR,
float2 uv0 : TEXCOORD0,
float2 uv1 : TEXCOORD1,
out float clip : SV_ClipDistance)
{
clip = dot(clipping_plane.xyz, mul(position, eye_space_xform)) + clipping_plane.w;
Multi_Texture_PS_Data ps_data;
ps_data.position = mul(clip_space_xform, position);
ps_data.color = color;
ps_data.uv0 = uv0;
ps_data.uv1 = uv1;
return ps_data;
}
float4 single_texture_ps(Single_Texture_PS_Data data) : SV_TARGET {
float4 out_color = data.color * texture0.Sample(sampler0, data.uv0);
#if defined(ALPHA_TEST_GT0)
if (out_color.a == 0.0f) discard;
#elif defined(ALPHA_TEST_LT80)
if (out_color.a >= 0.5f) discard;
#elif defined(ALPHA_TEST_GE80)
if (out_color.a < 0.5f) discard;
#endif
return out_color;
}
float4 multi_texture_mul_ps(Multi_Texture_PS_Data data) : SV_TARGET {
float4 out_color = data.color * texture0.Sample(sampler0, data.uv0) * texture1.Sample(sampler1, data.uv1);
#if defined(ALPHA_TEST_GT0)
if (out_color.a == 0.0f) discard;
#elif defined(ALPHA_TEST_LT80)
if (out_color.a >= 0.5f) discard;
#elif defined(ALPHA_TEST_GE80)
if (out_color.a < 0.5f) discard;
#endif
return out_color;
}
float4 multi_texture_add_ps(Multi_Texture_PS_Data data) : SV_TARGET {
float4 color_a = data.color * texture0.Sample(sampler0, data.uv0);
float4 color_b = texture1.Sample(sampler1, data.uv1);
float4 out_color = float4(
color_a.r + color_b.r,
color_a.g + color_b.g,
color_a.b + color_b.b,
color_a.a * color_b.a);
#if defined(ALPHA_TEST_GT0)
if (out_color.a == 0.0f) discard;
#elif defined(ALPHA_TEST_LT80)
if (out_color.a >= 0.5f) discard;
#elif defined(ALPHA_TEST_GE80)
if (out_color.a < 0.5f) discard;
#endif
return out_color;
}

View file

@ -0,0 +1,26 @@
#version 450
layout(set = 0, binding = 0) uniform sampler2D texture0;
layout(location = 0) in vec4 frag_color;
layout(location = 1) in vec2 frag_tex_coord;
layout(location = 3) in float frag_clip_dist;
layout(location = 0) out vec4 out_color;
layout (constant_id = 0) const int alpha_test_func = 0;
layout (constant_id = 2) const int clip_plane = 0;
void main() {
if (clip_plane != 0 && frag_clip_dist < 0.0) discard;
out_color = frag_color * texture(texture0, frag_tex_coord);
if (alpha_test_func == 1) {
if (out_color.a == 0.0f) discard;
} else if (alpha_test_func == 2) {
if (out_color.a >= 0.5f) discard;
} else if (alpha_test_func == 3) {
if (out_color.a < 0.5f) discard;
}
}

View file

@ -0,0 +1,34 @@
#version 450
// 128 bytes
layout(push_constant) uniform Transform {
mat4x4 clip_space_xform;
// a single-precision floating-point matrix with 3 columns and 4 rows
mat3x4 eye_space_xform;
vec4 clipping_plane; // in eye space
};
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec4 in_color;
layout(location = 2) in vec2 in_tex_coord;
layout(location = 0) out vec4 frag_color;
layout(location = 1) out vec2 frag_tex_coord;
layout(location = 3) out float frag_clip_dist;
layout (constant_id = 2) const int clip_plane = 0;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
vec4 p = vec4(in_position, 1.0);
gl_Position = clip_space_xform * p;
if (clip_plane != 0)
frag_clip_dist = dot(clipping_plane, vec4( p * eye_space_xform, 1.0));
frag_color = in_color;
frag_tex_coord = in_tex_coord;
}

View file

@ -0,0 +1,31 @@
#version 450
// 128 bytes
layout(push_constant) uniform Transform {
mat4x4 clip_space_xform;
// a single-precision floating-point matrix with 3 columns and 4 rows
mat3x4 eye_space_xform;
vec4 clipping_plane; // in eye space
};
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec4 in_color;
layout(location = 2) in vec2 in_tex_coord;
layout(location = 0) out vec4 frag_color;
layout(location = 1) out vec2 frag_tex_coord;
out gl_PerVertex {
vec4 gl_Position;
float gl_ClipDistance[1];
};
void main() {
vec4 p = vec4(in_position, 1.0);
gl_Position = clip_space_xform * p;
gl_ClipDistance[0] = dot(clipping_plane, vec4( p * eye_space_xform, 1.0));
frag_color = in_color;
frag_tex_coord = in_tex_coord;
}

7049
code/renderervk/stb_image.h Normal file

File diff suppressed because it is too large Load diff

121
code/renderervk/tr_Cull.c Normal file
View file

@ -0,0 +1,121 @@
#include "tr_local.h"
#include "tr_cvar.h"
#include "tr_globals.h"
/*
=================
Returns CULL_IN, CULL_CLIP, or CULL_OUT
=================
*/
int R_CullLocalBox (vec3_t bounds[2])
{
int i, j;
vec3_t transformed[8];
float dists[8];
vec3_t v;
cplane_t *frust;
int anyBack;
int front, back;
if ( r_nocull->integer ) {
return CULL_CLIP;
}
// transform into world space
for (i = 0 ; i < 8 ; i++) {
v[0] = bounds[i&1][0];
v[1] = bounds[(i>>1)&1][1];
v[2] = bounds[(i>>2)&1][2];
VectorCopy( tr.or.origin, transformed[i] );
VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] );
VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] );
VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] );
}
// check against frustum planes
anyBack = 0;
for (i = 0 ; i < 4 ; i++) {
frust = &tr.viewParms.frustum[i];
front = back = 0;
for (j = 0 ; j < 8 ; j++) {
dists[j] = DotProduct(transformed[j], frust->normal);
if ( dists[j] > frust->dist ) {
front = 1;
if ( back ) {
break; // a point is in front
}
} else {
back = 1;
}
}
if ( !front ) {
// all points were behind one of the planes
return CULL_OUT;
}
anyBack |= back;
}
if ( !anyBack ) {
return CULL_IN; // completely inside frustum
}
return CULL_CLIP; // partially clipped
}
static void R_LocalPointToWorld (vec3_t local, const orientationr_t * const pRT, vec3_t world)
{
world[0] = local[0] * pRT->axis[0][0] + local[1] * pRT->axis[1][0] + local[2] * pRT->axis[2][0] + pRT->origin[0];
world[1] = local[0] * pRT->axis[0][1] + local[1] * pRT->axis[1][1] + local[2] * pRT->axis[2][1] + pRT->origin[1];
world[2] = local[0] * pRT->axis[0][2] + local[1] * pRT->axis[1][2] + local[2] * pRT->axis[2][2] + pRT->origin[2];
}
int R_CullLocalPointAndRadius( vec3_t pt, float radius )
{
vec3_t transformed;
R_LocalPointToWorld( pt, &tr.or, transformed );
return R_CullPointAndRadius( transformed, radius );
}
/*
** R_CullPointAndRadius
*/
int R_CullPointAndRadius( vec3_t pt, float radius )
{
int i;
float dist;
cplane_t *frust;
qboolean mightBeClipped = qfalse;
if ( r_nocull->integer ) {
return CULL_CLIP;
}
// check against frustum planes
for (i = 0 ; i < 4 ; i++)
{
frust = &tr.viewParms.frustum[i];
dist = DotProduct( pt, frust->normal) - frust->dist;
if ( dist < -radius )
{
return CULL_OUT;
}
else if ( dist <= radius )
{
mightBeClipped = qtrue;
}
}
if ( mightBeClipped )
{
return CULL_CLIP;
}
return CULL_IN; // completely inside frustum
}

View file

@ -0,0 +1,286 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
#include "tr_globals.h"
#include "tr_cvar.h"
#include "vk_shade_geometry.h"
#include "ref_import.h"
#include "tr_light.h"
#include "tr_shader.h"
/*
All bones should be an identity orientation to display the mesh exactly
as it is specified.
For all other frames, the bones represent the transformation from the
orientation of the bone in the base frame to the orientation in this
frame.
*/
extern int R_ComputeLOD( trRefEntity_t *ent );
static int R_MDRCullModel( mdrHeader_t *header, trRefEntity_t *ent )
{
vec3_t bounds[2];
int i;
int frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
// compute frame pointers
mdrFrame_t* newFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
mdrFrame_t* oldFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.oldframe);
// cull bounding sphere ONLY if this is not an upscaled entity
if ( !ent->e.nonNormalizedAxes )
{
if ( ent->e.frame == ent->e.oldframe )
{
switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
{
// Ummm... yeah yeah I know we don't really have an md3 here.. but we pretend
// we do. After all, the purpose of mdrs are not that different, are they?
case CULL_OUT:
tr.pc.c_sphere_cull_md3_out++;
return CULL_OUT;
case CULL_IN:
tr.pc.c_sphere_cull_md3_in++;
return CULL_IN;
case CULL_CLIP:
tr.pc.c_sphere_cull_md3_clip++;
break;
}
}
else
{
int sphereCullB;
int sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
if ( newFrame == oldFrame )
{
sphereCullB = sphereCull;
}
else
{
sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
}
if ( sphereCull == sphereCullB )
{
if ( sphereCull == CULL_OUT )
{
tr.pc.c_sphere_cull_md3_out++;
return CULL_OUT;
}
else if ( sphereCull == CULL_IN )
{
tr.pc.c_sphere_cull_md3_in++;
return CULL_IN;
}
else
{
tr.pc.c_sphere_cull_md3_clip++;
}
}
}
}
// calculate a bounding box in the current coordinate system
for (i = 0 ; i < 3 ; i++)
{
bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
}
switch ( R_CullLocalBox( bounds ) )
{
case CULL_IN:
tr.pc.c_box_cull_md3_in++;
return CULL_IN;
case CULL_CLIP:
tr.pc.c_box_cull_md3_clip++;
return CULL_CLIP;
case CULL_OUT:
default:
tr.pc.c_box_cull_md3_out++;
return CULL_OUT;
}
}
static int R_MDRComputeFogNum( mdrHeader_t *header, trRefEntity_t *ent )
{
vec3_t localOrigin;
if ( tr.refdef.rd.rdflags & RDF_NOWORLDMODEL ) {
return 0;
}
int frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
// FIXME: non-normalized axis issues
mdrFrame_t* mdrFrame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
VectorAdd( ent->e.origin, mdrFrame->localOrigin, localOrigin );
int i, j;
for ( i = 1 ; i < tr.world->numfogs ; i++ )
{
fog_t* fog = &tr.world->fogs[i];
for ( j = 0 ; j < 3 ; j++ )
{
if ( localOrigin[j] - mdrFrame->radius >= fog->bounds[1][j] )
break;
if ( localOrigin[j] + mdrFrame->radius <= fog->bounds[0][j] )
break;
}
if ( j == 3 )
return i;
}
return 0;
}
// much stuff in there is just copied from R_AddMd3Surfaces in tr_mesh.c
void R_MDRAddAnimSurfaces( trRefEntity_t *ent )
{
shader_t* shader;
int i, j;
mdrHeader_t* header = (mdrHeader_t *) tr.currentModel->modelData;
qboolean personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
if( ent->e.renderfx & RF_WRAP_FRAMES )
{
ent->e.frame %= header->numFrames;
ent->e.oldframe %= header->numFrames;
}
// Validate the frames so there is no chance of a crash.
// This will write directly into the entity structure,
// so when the surfaces are rendered,
// they don't need to be range checked again.
if ((ent->e.frame >= header->numFrames) || (ent->e.frame < 0) ||
(ent->e.oldframe >= header->numFrames) || (ent->e.oldframe < 0) )
{
ri.Printf( PRINT_ALL, "R_MDRAddAnimSurfaces: no such frame %d to %d for '%s'\n", ent->e.oldframe, ent->e.frame, tr.currentModel->name );
ent->e.frame = 0;
ent->e.oldframe = 0;
}
//
// cull the entire model if merged bounding box of both frames
// is outside the view frustum.
//
int cull = R_MDRCullModel(header, ent);
if ( cull == CULL_OUT ) {
return;
}
// figure out the current LOD of the model we're rendering, and set the lod pointer respectively.
int lodnum = 0;
if ( tr.currentModel->numLods > 1 )
lodnum = R_ComputeLOD( ent );
// check whether this model has as that many LODs at all. If not, try the closest thing we got.
if(header->numLODs <= 0)
return;
if(header->numLODs <= lodnum)
lodnum = header->numLODs - 1;
mdrLOD_t* lod = (mdrLOD_t *)( (unsigned char *)header + header->ofsLODs);
for(i = 0; i < lodnum; i++)
{
lod = (mdrLOD_t *) ((unsigned char *)lod + lod->ofsEnd);
}
// set up lighting
if ( !personalModel || r_shadows->integer > 1 )
{
R_SetupEntityLighting( &tr.refdef, ent );
}
// fogNum?
int fogNum = R_MDRComputeFogNum( header, ent );
mdrSurface_t* surface = (mdrSurface_t *)( (unsigned char *)lod + lod->ofsSurfaces );
for ( i = 0 ; i < lod->numSurfaces ; i++ )
{
if(ent->e.customShader)
shader = R_GetShaderByHandle(ent->e.customShader);
else if((ent->e.customSkin > 0) && (ent->e.customSkin < tr.numSkins))
{
skin_t* skin = tr.skins[ent->e.customSkin];
shader = tr.defaultShader;
for(j = 0; j < skin->numSurfaces; j++)
{
if (0 == strcmp(skin->pSurfaces[j].name, surface->name))
{
shader = skin->pSurfaces[j].shader;
break;
}
}
}
else if(surface->shaderIndex > 0)
shader = R_GetShaderByHandle( surface->shaderIndex );
else
shader = tr.defaultShader;
// we will add shadows even if the main object isn't visible in the view
// stencil shadows can't do personal models unless I polyhedron clip
if ( (personalModel == 0) && (r_shadows->integer == 2) && (fogNum == 0)
&& !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) )
&& (shader->sort == SS_OPAQUE) )
{
R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, qfalse );
}
// projection shadows work fine with personal models
if ( (r_shadows->integer == 3) && (fogNum == 0)
&& (ent->e.renderfx & RF_SHADOW_PLANE ) && (shader->sort == SS_OPAQUE) )
{
R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, qfalse );
}
if (!personalModel)
R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
surface = (mdrSurface_t *)( (byte *)surface + surface->ofsEnd );
}
}

View file

@ -0,0 +1,30 @@
#include "ref_import.h"
#include "tr_backend.h"
#include "R_PrintMat.h"
#include "glConfig.h"
backEndState_t backEnd;
void R_ClearBackendState(void)
{
ri.Printf(PRINT_ALL, " backend state cleared. \n");
// clear all our internal state
memset( &backEnd, 0, sizeof( backEnd ) );
int width, height;
R_GetWinResolution(&width, &height);
backEnd.viewParms.viewportWidth = width;
backEnd.viewParms.viewportHeight = height;
}
void R_PrintBackEnd_OR_f(void)
{
// in world coordinates
printMat1x3f("backEnd.or.origin", backEnd.or.origin);
// orientation in world
printMat3x3f("backEnd.or.axis", backEnd.or.axis);
// viewParms->or.origin in local coordinates
printMat1x3f("backEnd.or.viewOrigin", backEnd.or.viewOrigin);
printMat4x4f("backEnd.or.modelMatrix", backEnd.or.modelMatrix);
}

View file

@ -0,0 +1,39 @@
#ifndef TR_BACKEND_H_
#define TR_BACKEND_H_
#include "tr_local.h"
typedef struct {
int c_surfaces;
int c_shaders;
int c_vertexes;
int c_indexes;
int c_totalIndexes;
int c_dlightVertexes;
int c_dlightIndexes;
int msec; // total msec for backend run
} backEndCounters_t;
// all state modified by the back end is seperated
// from the front end state
typedef struct {
trRefdef_t refdef;
viewParms_t viewParms;
orientationr_t or;
backEndCounters_t pc;
trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
trRefEntity_t* currentEntity;
unsigned char Color2D[4];
qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes
qboolean isHyperspace;
} backEndState_t;
extern backEndState_t backEnd;
void R_ClearBackendState(void);
void R_PrintBackEnd_OR_f(void);
#endif

1890
code/renderervk/tr_bsp.c Normal file

File diff suppressed because it is too large Load diff

670
code/renderervk/tr_cmds.c Normal file
View file

@ -0,0 +1,670 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
#include "tr_globals.h"
#include "tr_backend.h"
#include "tr_cvar.h"
#include "ref_import.h"
#include "vk_instance.h"
#include "vk_frame.h"
#include "vk_screenshot.h"
#include "vk_shade_geometry.h"
#include "RB_ShowImages.h"
#include "R_PrintMat.h"
#include "tr_light.h"
static renderCommandList_t BE_Commands;
/*
============
R_GetCommandBuffer
make sure there is enough command space, waiting on the
render thread if needed.
============
*/
void* R_GetCommandBuffer( int bytes )
{
renderCommandList_t *cmdList = &BE_Commands;
// always leave room for the end of list command
if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS )
{
if ( bytes > MAX_RENDER_COMMANDS - 4 ) {
ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
}
// if we run out of room, just start dropping commands
return NULL;
}
cmdList->used += bytes;
return cmdList->cmds + cmdList->used - bytes;
}
/*
=============
submits a single 'draw' command into the command queue
=============
*/
void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs )
{
drawSurfsCommand_t* cmd = (drawSurfsCommand_t*) R_GetCommandBuffer( sizeof(drawSurfsCommand_t) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_DRAW_SURFS;
cmd->drawSurfs = drawSurfs;
cmd->numDrawSurfs = numDrawSurfs;
cmd->refdef = tr.refdef;
cmd->viewParms = tr.viewParms;
}
/*
=============
RE_SetColor
Passing NULL will set the color to white
=============
*/
void RE_SetColor( const float *rgba )
{
if ( !tr.registered ) {
return;
}
setColorCommand_t* cmd = (setColorCommand_t*) R_GetCommandBuffer( sizeof(setColorCommand_t) );
if ( !cmd ) {
return;
}
cmd->commandId = RC_SET_COLOR;
if(rgba)
{
cmd->color[0] = rgba[0];
cmd->color[1] = rgba[1];
cmd->color[2] = rgba[2];
cmd->color[3] = rgba[3];
}
else
{
// color white
cmd->color[0] = 1.0f;
cmd->color[1] = 1.0f;
cmd->color[2] = 1.0f;
cmd->color[3] = 1.0f;
}
}
void RE_StretchPic ( float x, float y, float w, float h,
float s1, float t1, float s2, float t2, qhandle_t hShader )
{
if (!tr.registered) {
return;
}
stretchPicCommand_t* cmd = (stretchPicCommand_t*) R_GetCommandBuffer(sizeof(stretchPicCommand_t));
if ( !cmd ) {
return;
}
cmd->commandId = RC_STRETCH_PIC;
cmd->shader = R_GetShaderByHandle( hShader );
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->s1 = s1;
cmd->t1 = t1;
cmd->s2 = s2;
cmd->t2 = t2;
}
void RE_BeginFrame( stereoFrame_t stereoFrame )
{
if ( !tr.registered ) {
return;
}
// use the other buffers next frame, because another CPU
// may still be rendering into the current ones
// draw buffer stuff
drawBufferCommand_t* cmd = (drawBufferCommand_t*) R_GetCommandBuffer(sizeof(drawBufferCommand_t));
if ( !cmd ) {
return;
}
cmd->commandId = RC_DRAW_BUFFER;
}
/*
=============
RE_EndFrame
Returns the number of msec spent in the back end
=============
*/
void RE_EndFrame( int *frontEndMsec, int *backEndMsec )
{
if ( !tr.registered ) {
return;
}
swapBuffersCommand_t* cmd = (swapBuffersCommand_t*) R_GetCommandBuffer(sizeof(swapBuffersCommand_t));
if ( !cmd ) {
return;
}
cmd->commandId = RC_SWAP_BUFFERS;
R_IssueRenderCommands( qtrue );
R_InitNextFrame();
if ( frontEndMsec ) {
*frontEndMsec = tr.frontEndMsec;
}
tr.frontEndMsec = 0;
if ( backEndMsec ) {
*backEndMsec = backEnd.pc.msec;
}
backEnd.pc.msec = 0;
}
/*
==================
RB_RenderDrawSurfList
==================
*/
static void RB_RenderDrawSurfList( drawSurf_t* drawSurfs, int numDrawSurfs )
{
shader_t *shader, *oldShader;
int fogNum, oldFogNum;
int dlighted, oldDlighted;
// save original time for entity shader offsets
float originalTime = backEnd.refdef.floatTime;
// Any mirrored or portaled views have already been drawn,
// so prepare to actually render the visible surfaces for this view
// clear the z buffer, set the modelview, etc
// RB_BeginDrawingView ();
// we will need to change the projection matrix before drawing
// 2D images again
backEnd.projection2D = qfalse;
// ensures that depth writes are enabled for the depth clear
// VULKAN
vk_clearDepthStencilAttachments();
if ( backEnd.refdef.rd.rdflags & RDF_HYPERSPACE )
{
//RB_Hyperspace();
// A player has predicted a teleport, but hasn't arrived yet
const float c = ( backEnd.refdef.rd.time & 255 ) / 255.0f;
const float color[4] = { c, c, c, 1 };
// so short, do we really need this?
vk_clearColorAttachments(color);
backEnd.isHyperspace = qtrue;
}
else
{
backEnd.isHyperspace = qfalse;
}
// draw everything
int entityNum;
int oldEntityNum = -1;
backEnd.currentEntity = &tr.worldEntity;
oldShader = NULL;
oldFogNum = -1;
oldDlighted = qfalse;
int oldSort = -1;
backEnd.pc.c_surfaces += numDrawSurfs;
drawSurf_t* drawSurf;
int i;
for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++)
{
if ( (int)drawSurf->sort == oldSort ) {
// fast path, same as previous sort
rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
continue;
}
oldSort = drawSurf->sort;
R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
//
// change the tess parameters if needed
// a "entityMergable" shader is a shader that can have surfaces from seperate
// entities merged into a single batch, like smoke and blood puff sprites
if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted
|| ( entityNum != oldEntityNum && !shader->entityMergable ) ) {
if (oldShader != NULL) {
RB_EndSurface();
}
RB_BeginSurface( shader, fogNum );
oldShader = shader;
oldFogNum = fogNum;
oldDlighted = dlighted;
}
//
// change the modelview matrix if needed
//
if ( entityNum != oldEntityNum )
{
if ( entityNum != REFENTITYNUM_WORLD )
{
backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
// we have to reset the shaderTime as well otherwise image animations start
// from the wrong frame
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
// set up the transformation matrix
R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or );
// set up the dynamic lighting if needed
if ( backEnd.currentEntity->needDlights ) {
R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
}
if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) {
// hack the depth range to prevent view model from poking into walls
}
}
else
{
backEnd.currentEntity = &tr.worldEntity;
backEnd.refdef.floatTime = originalTime;
backEnd.or = backEnd.viewParms.world;
// we have to reset the shaderTime as well otherwise image animations on
// the world (like water) continue with the wrong frame
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
}
// VULKAN
set_modelview_matrix(backEnd.or.modelMatrix);
oldEntityNum = entityNum;
}
// add the triangles for this surface
rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
}
backEnd.refdef.floatTime = originalTime;
// draw the contents of the last shader batch
if (oldShader != NULL) {
RB_EndSurface();
}
// go back to the world modelview matrix
set_modelview_matrix(backEnd.viewParms.world.modelMatrix);
// darken down any stencil shadows
RB_ShadowFinish();
}
void RB_StretchPic( const stretchPicCommand_t * const cmd )
{
if ( qfalse == backEnd.projection2D )
{
backEnd.projection2D = qtrue;
// set 2D virtual screen size
// set time for 2D shaders
int t = ri.Milliseconds();
backEnd.refdef.rd.time = t;
backEnd.refdef.floatTime = t * 0.001f;
}
if ( cmd->shader != tess.shader )
{
if ( tess.numIndexes ) {
RB_EndSurface();
}
backEnd.currentEntity = &backEnd.entity2D;
RB_BeginSurface(cmd->shader, 0 );
}
RB_CHECKOVERFLOW( 4, 6 );
const unsigned int n0 = tess.numVertexes;
const unsigned int n1 = n0 + 1;
const unsigned int n2 = n0 + 2;
const unsigned int n3 = n0 + 3;
uint32_t numIndexes = tess.numIndexes;
tess.indexes[ numIndexes ] = n3;
tess.indexes[ numIndexes + 1 ] = n0;
tess.indexes[ numIndexes + 2 ] = n2;
tess.indexes[ numIndexes + 3 ] = n2;
tess.indexes[ numIndexes + 4 ] = n0;
tess.indexes[ numIndexes + 5 ] = n1;
// TODO: verify does coding this way run faster in release mode ?
// coding this way do harm to debug version because of
// introduce additional 4 function call.
memcpy(tess.vertexColors[ n0 ], backEnd.Color2D, 4);
memcpy(tess.vertexColors[ n1 ], backEnd.Color2D, 4);
memcpy(tess.vertexColors[ n2 ], backEnd.Color2D, 4);
memcpy(tess.vertexColors[ n3 ], backEnd.Color2D, 4);
tess.xyz[ n0 ][0] = cmd->x;
tess.xyz[ n0 ][1] = cmd->y;
tess.xyz[ n0 ][2] = 0;
tess.xyz[ n1 ][0] = cmd->x + cmd->w;
tess.xyz[ n1 ][1] = cmd->y;
tess.xyz[ n1 ][2] = 0;
tess.xyz[ n2 ][0] = cmd->x + cmd->w;
tess.xyz[ n2 ][1] = cmd->y + cmd->h;
tess.xyz[ n2 ][2] = 0;
tess.xyz[ n3 ][0] = cmd->x;
tess.xyz[ n3 ][1] = cmd->y + cmd->h;
tess.xyz[ n3 ][2] = 0;
tess.texCoords[ n0 ][0][0] = cmd->s1;
tess.texCoords[ n0 ][0][1] = cmd->t1;
tess.texCoords[ n1 ][0][0] = cmd->s2;
tess.texCoords[ n1 ][0][1] = cmd->t1;
tess.texCoords[ n2 ][0][0] = cmd->s2;
tess.texCoords[ n2 ][0][1] = cmd->t2;
tess.texCoords[ n3 ][0][0] = cmd->s1;
tess.texCoords[ n3 ][0][1] = cmd->t2;
tess.numVertexes += 4;
tess.numIndexes += 6;
}
static void R_PerformanceCounters( void )
{
if (r_speeds->integer == 1) {
ri.Printf (PRINT_ALL, "%i/%i shaders/surfs %i leafs %i verts %i/%i tris\n",
backEnd.pc.c_shaders, backEnd.pc.c_surfaces, tr.pc.c_leafs, backEnd.pc.c_vertexes,
backEnd.pc.c_indexes/3, backEnd.pc.c_totalIndexes/3);
} else if (r_speeds->integer == 2) {
ri.Printf (PRINT_ALL, "(patch) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
tr.pc.c_sphere_cull_patch_in, tr.pc.c_sphere_cull_patch_clip, tr.pc.c_sphere_cull_patch_out,
tr.pc.c_box_cull_patch_in, tr.pc.c_box_cull_patch_clip, tr.pc.c_box_cull_patch_out );
ri.Printf (PRINT_ALL, "(md3) %i sin %i sclip %i sout %i bin %i bclip %i bout\n",
tr.pc.c_sphere_cull_md3_in, tr.pc.c_sphere_cull_md3_clip, tr.pc.c_sphere_cull_md3_out,
tr.pc.c_box_cull_md3_in, tr.pc.c_box_cull_md3_clip, tr.pc.c_box_cull_md3_out );
} else if (r_speeds->integer == 3) {
ri.Printf (PRINT_ALL, "viewcluster: %i\n", tr.viewCluster );
} else if (r_speeds->integer == 4) {
if ( backEnd.pc.c_dlightVertexes ) {
ri.Printf (PRINT_ALL, "dlight srf:%i culled:%i verts:%i tris:%i\n",
tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled,
backEnd.pc.c_dlightVertexes, backEnd.pc.c_dlightIndexes / 3 );
}
}
memset( &tr.pc, 0, sizeof( tr.pc ) );
memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
}
/*
====================
This function will be called synchronously if running without
smp extensions, or asynchronously by another thread.
====================
*/
void R_IssueRenderCommands( qboolean runPerformanceCounters )
{
if(runPerformanceCounters)
{
R_PerformanceCounters();
}
// actually start the commands going
// let it start on the new batch
// RB_ExecuteRenderCommands( cmdList->cmds );
int t1 = ri.Milliseconds ();
// add an end-of-list command
*(int *)(BE_Commands.cmds + BE_Commands.used) = RC_END_OF_LIST;
const void * data = BE_Commands.cmds;
while(1)
{
const int T = *(const int *)data;
switch ( T )
{
case RC_SET_COLOR:
{
const setColorCommand_t * const cmd = data;
backEnd.Color2D[0] = cmd->color[0] * 255;
backEnd.Color2D[1] = cmd->color[1] * 255;
backEnd.Color2D[2] = cmd->color[2] * 255;
backEnd.Color2D[3] = cmd->color[3] * 255;
data += sizeof(setColorCommand_t);
} break;
case RC_STRETCH_PIC:
{
const stretchPicCommand_t * const cmd = data;
RB_StretchPic( cmd );
data += sizeof(stretchPicCommand_t);
} break;
case RC_DRAW_SURFS:
{
const drawSurfsCommand_t * const cmd = (const drawSurfsCommand_t *)data;
// RB_DrawSurfs( cmd );
// finish any 2D drawing if needed
if ( tess.numIndexes ) {
RB_EndSurface();
}
backEnd.refdef = cmd->refdef;
backEnd.viewParms = cmd->viewParms;
RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );
data += sizeof(drawSurfsCommand_t);
} break;
case RC_DRAW_BUFFER:
{
// data = RB_DrawBuffer( data );
// const drawBufferCommand_t * const cmd = (const drawBufferCommand_t *)data;
vk_resetGeometryBuffer();
// VULKAN
vk_begin_frame();
data += sizeof(drawBufferCommand_t);
// begin_frame_called = qtrue;
} break;
case RC_SWAP_BUFFERS:
{
// data = RB_SwapBuffers( data );
// finish any 2D drawing if needed
RB_EndSurface();
// texture swapping test
if ( r_showImages->integer ) {
RB_ShowImages(tr.images, tr.numImages);
}
// VULKAN
vk_end_frame();
data += sizeof(swapBuffersCommand_t);
} break;
case RC_SCREENSHOT:
{
const screenshotCommand_t * const cmd = data;
RB_TakeScreenshot( cmd->width, cmd->height, cmd->fileName, cmd->jpeg);
data += sizeof(screenshotCommand_t);
} break;
case RC_VIDEOFRAME:
{
const videoFrameCommand_t * const cmd = data;
RB_TakeVideoFrameCmd( cmd );
data += sizeof(videoFrameCommand_t);
} break;
case RC_END_OF_LIST:
// stop rendering on this thread
backEnd.pc.msec = ri.Milliseconds () - t1;
BE_Commands.used = 0;
return;
}
}
}
/*
=============
FixRenderCommandList
https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated
but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces
to be rendered with bad shaders. To fix this, need to go through all render commands and fix
sortedIndex.
==============
*/
void FixRenderCommandList( int newShader )
{
renderCommandList_t *cmdList = &BE_Commands;
if( cmdList ) {
const void *curCmd = cmdList->cmds;
while ( 1 ) {
switch ( *(const int *)curCmd ) {
case RC_SET_COLOR:
{
const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd;
curCmd = (const void *)(sc_cmd + 1);
break;
}
case RC_STRETCH_PIC:
{
const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd;
curCmd = (const void *)(sp_cmd + 1);
break;
}
case RC_DRAW_SURFS:
{
int i;
drawSurf_t *drawSurf;
shader_t *shader;
int fogNum;
int entityNum;
int dlightMap;
int sortedIndex;
const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd;
for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {
R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap );
sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1));
if( sortedIndex >= newShader ) {
sortedIndex++;
drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
}
}
curCmd = (const void *)(ds_cmd + 1);
break;
}
case RC_DRAW_BUFFER:
{
const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd;
curCmd = (const void *)(db_cmd + 1);
break;
}
case RC_SWAP_BUFFERS:
{
const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd;
curCmd = (const void *)(sb_cmd + 1);
break;
}
case RC_END_OF_LIST:
default:
return;
}
}
}
}

627
code/renderervk/tr_curve.c Normal file
View file

@ -0,0 +1,627 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
#include "tr_cvar.h"
#include "ref_import.h"
/*
This file does all of the processing necessary to turn a raw grid of points
read from the map file into a srfGridMesh_t ready for rendering.
The level of detail solution is direction independent, based only on subdivided
distance from the true curve.
Only a single entry point:
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
*/
/*
============
LerpDrawVert
============
*/
static void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) {
out->xyz[0] = 0.5f * (a->xyz[0] + b->xyz[0]);
out->xyz[1] = 0.5f * (a->xyz[1] + b->xyz[1]);
out->xyz[2] = 0.5f * (a->xyz[2] + b->xyz[2]);
out->st[0] = 0.5f * (a->st[0] + b->st[0]);
out->st[1] = 0.5f * (a->st[1] + b->st[1]);
out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]);
out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]);
out->color[0] = (a->color[0] + b->color[0]) >> 1;
out->color[1] = (a->color[1] + b->color[1]) >> 1;
out->color[2] = (a->color[2] + b->color[2]) >> 1;
out->color[3] = (a->color[3] + b->color[3]) >> 1;
}
/*
============
Transpose
============
*/
static void Transpose( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
int i, j;
drawVert_t temp;
if ( width > height ) {
for ( i = 0 ; i < height ; i++ ) {
for ( j = i + 1 ; j < width ; j++ ) {
if ( j < height ) {
// swap the value
temp = ctrl[j][i];
ctrl[j][i] = ctrl[i][j];
ctrl[i][j] = temp;
} else {
// just copy
ctrl[j][i] = ctrl[i][j];
}
}
}
} else {
for ( i = 0 ; i < width ; i++ ) {
for ( j = i + 1 ; j < height ; j++ ) {
if ( j < width ) {
// swap the value
temp = ctrl[i][j];
ctrl[i][j] = ctrl[j][i];
ctrl[j][i] = temp;
} else {
// just copy
ctrl[i][j] = ctrl[j][i];
}
}
}
}
}
/*
=================
MakeMeshNormals
Handles all the complicated wrapping and degenerate cases
=================
*/
static void MakeMeshNormals( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
int i, j, k, dist;
vec3_t normal;
vec3_t sum;
int count;
vec3_t base;
vec3_t delta;
int x, y;
drawVert_t *dv;
vec3_t around[8], temp;
qboolean good[8];
qboolean wrapWidth, wrapHeight;
float len;
static int neighbors[8][2] = {
{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
};
wrapWidth = qfalse;
for ( i = 0 ; i < height ; i++ ) {
VectorSubtract( ctrl[i][0].xyz, ctrl[i][width-1].xyz, delta );
len = VectorLengthSquared( delta );
if ( len > 1.0 ) {
break;
}
}
if ( i == height ) {
wrapWidth = qtrue;
}
wrapHeight = qfalse;
for ( i = 0 ; i < width ; i++ ) {
VectorSubtract( ctrl[0][i].xyz, ctrl[height-1][i].xyz, delta );
len = VectorLengthSquared( delta );
if ( len > 1.0 ) {
break;
}
}
if ( i == width) {
wrapHeight = qtrue;
}
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
count = 0;
dv = &ctrl[j][i];
VectorCopy( dv->xyz, base );
for ( k = 0 ; k < 8 ; k++ ) {
VectorClear( around[k] );
good[k] = qfalse;
for ( dist = 1 ; dist <= 3 ; dist++ ) {
x = i + neighbors[k][0] * dist;
y = j + neighbors[k][1] * dist;
if ( wrapWidth ) {
if ( x < 0 ) {
x = width - 1 + x;
} else if ( x >= width ) {
x = 1 + x - width;
}
}
if ( wrapHeight ) {
if ( y < 0 ) {
y = height - 1 + y;
} else if ( y >= height ) {
y = 1 + y - height;
}
}
if ( x < 0 || x >= width || y < 0 || y >= height ) {
break; // edge of patch
}
VectorSubtract( ctrl[y][x].xyz, base, temp );
if ( VectorNormalize2( temp, temp ) == 0 ) {
continue; // degenerate edge, get more dist
} else {
good[k] = qtrue;
VectorCopy( temp, around[k] );
break; // good edge
}
}
}
VectorClear( sum );
for ( k = 0 ; k < 8 ; k++ ) {
if ( !good[k] || !good[(k+1)&7] ) {
continue; // didn't get two points
}
CrossProduct( around[(k+1)&7], around[k], normal );
if ( VectorNormalize2( normal, normal ) == 0 ) {
continue;
}
VectorAdd( normal, sum, sum );
count++;
}
if ( count == 0 ) {
//printf("bad normal\n");
count = 1;
}
VectorNormalize2( sum, dv->normal );
}
}
}
/*
============
InvertCtrl
============
*/
static void InvertCtrl( int width, int height, drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
int i, j;
drawVert_t temp;
for ( i = 0 ; i < height ; i++ ) {
for ( j = 0 ; j < width/2 ; j++ ) {
temp = ctrl[i][j];
ctrl[i][j] = ctrl[i][width-1-j];
ctrl[i][width-1-j] = temp;
}
}
}
/*
=================
InvertErrorTable
=================
*/
static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {
int i;
float copy[2][MAX_GRID_SIZE];
memcpy( copy, errorTable, sizeof( copy ) );
for ( i = 0 ; i < width ; i++ ) {
errorTable[1][i] = copy[0][i]; //[width-1-i];
}
for ( i = 0 ; i < height ; i++ ) {
errorTable[0][i] = copy[1][height-1-i];
}
}
/*
==================
PutPointsOnCurve
==================
*/
static void PutPointsOnCurve( drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
int width, int height ) {
int i, j;
drawVert_t prev, next;
for ( i = 0 ; i < width ; i++ ) {
for ( j = 1 ; j < height ; j += 2 ) {
LerpDrawVert( &ctrl[j][i], &ctrl[j+1][i], &prev );
LerpDrawVert( &ctrl[j][i], &ctrl[j-1][i], &next );
LerpDrawVert( &prev, &next, &ctrl[j][i] );
}
}
for ( j = 0 ; j < height ; j++ ) {
for ( i = 1 ; i < width ; i += 2 ) {
LerpDrawVert( &ctrl[j][i], &ctrl[j][i+1], &prev );
LerpDrawVert( &ctrl[j][i], &ctrl[j][i-1], &next );
LerpDrawVert( &prev, &next, &ctrl[j][i] );
}
}
}
/*
=================
R_CreateSurfaceGridMesh
=================
*/
srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height,
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE] ) {
int i, j, size;
drawVert_t *vert;
vec3_t tmpVec;
srfGridMesh_t *grid;
// copy the results out to a grid
size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
#ifdef PATCH_STITCHING
grid = /*ri.Hunk_Alloc*/ (srfGridMesh_t*) ri.Malloc( size );
memset(grid, 0, size);
grid->widthLodError = /*ri.Hunk_Alloc*/ (float*) ri.Malloc( width * 4 );
memcpy( grid->widthLodError, errorTable[0], width * 4 );
grid->heightLodError = /*ri.Hunk_Alloc*/ (float*) ri.Malloc( height * 4 );
memcpy( grid->heightLodError, errorTable[1], height * 4 );
#else
grid = ri.Hunk_Alloc( size );
memset(grid, 0, size);
grid->widthLodError = ri.Hunk_Alloc( width * 4 );
memcpy( grid->widthLodError, errorTable[0], width * 4 );
grid->heightLodError = ri.Hunk_Alloc( height * 4 );
memcpy( grid->heightLodError, errorTable[1], height * 4 );
#endif
grid->width = width;
grid->height = height;
grid->surfaceType = SF_GRID;
ClearBounds( grid->meshBounds[0], grid->meshBounds[1] );
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
vert = &grid->verts[j*width+i];
*vert = ctrl[j][i];
AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] );
}
}
// compute local origin and bounds
VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin );
VectorScale( grid->localOrigin, 0.5f, grid->localOrigin );
VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec );
grid->meshRadius = VectorLength( tmpVec );
VectorCopy( grid->localOrigin, grid->lodOrigin );
grid->lodRadius = grid->meshRadius;
//
return grid;
}
/*
=================
R_FreeSurfaceGridMesh
=================
*/
void R_FreeSurfaceGridMesh( srfGridMesh_t *grid ) {
ri.Free(grid->widthLodError);
ri.Free(grid->heightLodError);
ri.Free(grid);
}
/*
=================
R_SubdividePatchToGrid
=================
*/
srfGridMesh_t *R_SubdividePatchToGrid( int width, int height,
drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
int i, j, k, l;
drawVert_t prev, next, mid;
float len, maxLen;
int dir;
int t;
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
float errorTable[2][MAX_GRID_SIZE];
for ( i = 0 ; i < width ; i++ ) {
for ( j = 0 ; j < height ; j++ ) {
ctrl[j][i] = points[j*width+i];
}
}
for ( dir = 0 ; dir < 2 ; dir++ ) {
for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
errorTable[dir][j] = 0;
}
// horizontal subdivisions
for ( j = 0 ; j + 2 < width ; j += 2 ) {
// check subdivided midpoints against control points
// FIXME: also check midpoints of adjacent patches against the control points
// this would basically stitch all patches in the same LOD group together.
maxLen = 0;
for ( i = 0 ; i < height ; i++ ) {
vec3_t midxyz;
vec3_t midxyz2;
vec3_t dir;
vec3_t projected;
float d;
// calculate the point on the curve
for ( l = 0 ; l < 3 ; l++ ) {
midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j+1].xyz[l] * 2
+ ctrl[i][j+2].xyz[l] ) * 0.25f;
}
// see how far off the line it is
// using dist-from-line will not account for internal
// texture warping, but it gives a lot less polygons than
// dist-from-midpoint
VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
VectorSubtract( ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir );
VectorNormalize( dir );
d = DotProduct( midxyz, dir );
VectorScale( dir, d, projected );
VectorSubtract( midxyz, projected, midxyz2);
len = VectorLengthSquared( midxyz2 ); // we will do the sqrt later
if ( len > maxLen ) {
maxLen = len;
}
}
maxLen = sqrt(maxLen);
// if all the points are on the lines, remove the entire columns
if ( maxLen < 0.1f ) {
errorTable[dir][j+1] = 999;
continue;
}
// see if we want to insert subdivided columns
if ( width + 2 > MAX_GRID_SIZE ) {
errorTable[dir][j+1] = 1.0f/maxLen;
continue; // can't subdivide any more
}
if ( maxLen <= r_subdivisions->value ) {
errorTable[dir][j+1] = 1.0f/maxLen;
continue; // didn't need subdivision
}
errorTable[dir][j+2] = 1.0f/maxLen;
// insert two columns and replace the peak
width += 2;
for ( i = 0 ; i < height ; i++ ) {
LerpDrawVert( &ctrl[i][j], &ctrl[i][j+1], &prev );
LerpDrawVert( &ctrl[i][j+1], &ctrl[i][j+2], &next );
LerpDrawVert( &prev, &next, &mid );
for ( k = width - 1 ; k > j + 3 ; k-- ) {
ctrl[i][k] = ctrl[i][k-2];
}
ctrl[i][j + 1] = prev;
ctrl[i][j + 2] = mid;
ctrl[i][j + 3] = next;
}
// back up and recheck this set again, it may need more subdivision
j -= 2;
}
Transpose( width, height, ctrl );
t = width;
width = height;
height = t;
}
// put all the aproximating points on the curve
PutPointsOnCurve( ctrl, width, height );
// cull out any rows or columns that are colinear
for ( i = 1 ; i < width-1 ; i++ ) {
if ( errorTable[0][i] != 999 ) {
continue;
}
for ( j = i+1 ; j < width ; j++ ) {
for ( k = 0 ; k < height ; k++ ) {
ctrl[k][j-1] = ctrl[k][j];
}
errorTable[0][j-1] = errorTable[0][j];
}
width--;
}
for ( i = 1 ; i < height-1 ; i++ ) {
if ( errorTable[1][i] != 999 ) {
continue;
}
for ( j = i+1 ; j < height ; j++ ) {
for ( k = 0 ; k < width ; k++ ) {
ctrl[j-1][k] = ctrl[j][k];
}
errorTable[1][j-1] = errorTable[1][j];
}
height--;
}
#if 1
// flip for longest tristrips as an optimization
// the results should be visually identical with or
// without this step
if ( height > width ) {
Transpose( width, height, ctrl );
InvertErrorTable( errorTable, width, height );
t = width;
width = height;
height = t;
InvertCtrl( width, height, ctrl );
}
#endif
// calculate normals
MakeMeshNormals( width, height, ctrl );
return R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
}
/*
===============
R_GridInsertColumn
===============
*/
srfGridMesh_t *R_GridInsertColumn( srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror ) {
int i, j;
int width, height, oldwidth;
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
float errorTable[2][MAX_GRID_SIZE];
float lodRadius;
vec3_t lodOrigin;
oldwidth = 0;
width = grid->width + 1;
if (width > MAX_GRID_SIZE)
return NULL;
height = grid->height;
for (i = 0; i < width; i++) {
if (i == column) {
//insert new column
for (j = 0; j < grid->height; j++) {
LerpDrawVert( &grid->verts[j * grid->width + i-1], &grid->verts[j * grid->width + i], &ctrl[j][i] );
if (j == row)
VectorCopy(point, ctrl[j][i].xyz);
}
errorTable[0][i] = loderror;
continue;
}
errorTable[0][i] = grid->widthLodError[oldwidth];
for (j = 0; j < grid->height; j++) {
ctrl[j][i] = grid->verts[j * grid->width + oldwidth];
}
oldwidth++;
}
for (j = 0; j < grid->height; j++) {
errorTable[1][j] = grid->heightLodError[j];
}
// put all the aproximating points on the curve
//PutPointsOnCurve( ctrl, width, height );
// calculate normals
MakeMeshNormals( width, height, ctrl );
VectorCopy(grid->lodOrigin, lodOrigin);
lodRadius = grid->lodRadius;
// free the old grid
R_FreeSurfaceGridMesh(grid);
// create a new grid
grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
grid->lodRadius = lodRadius;
VectorCopy(lodOrigin, grid->lodOrigin);
return grid;
}
/*
===============
R_GridInsertRow
===============
*/
srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) {
int i, j;
int width, height, oldheight;
drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
float errorTable[2][MAX_GRID_SIZE];
float lodRadius;
vec3_t lodOrigin;
oldheight = 0;
width = grid->width;
height = grid->height + 1;
if (height > MAX_GRID_SIZE)
return NULL;
for (i = 0; i < height; i++) {
if (i == row) {
//insert new row
for (j = 0; j < grid->width; j++) {
LerpDrawVert( &grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );
if (j == column)
VectorCopy(point, ctrl[i][j].xyz);
}
errorTable[1][i] = loderror;
continue;
}
errorTable[1][i] = grid->heightLodError[oldheight];
for (j = 0; j < grid->width; j++) {
ctrl[i][j] = grid->verts[oldheight * grid->width + j];
}
oldheight++;
}
for (j = 0; j < grid->width; j++) {
errorTable[0][j] = grid->widthLodError[j];
}
// put all the aproximating points on the curve
//PutPointsOnCurve( ctrl, width, height );
// calculate normals
MakeMeshNormals( width, height, ctrl );
VectorCopy(grid->lodOrigin, lodOrigin);
lodRadius = grid->lodRadius;
// free the old grid
R_FreeSurfaceGridMesh(grid);
// create a new grid
grid = R_CreateSurfaceGridMesh( width, height, ctrl, errorTable );
grid->lodRadius = lodRadius;
VectorCopy(lodOrigin, grid->lodOrigin);
return grid;
}

169
code/renderervk/tr_cvar.c Normal file
View file

@ -0,0 +1,169 @@
#include "tr_cvar.h"
#include "ref_import.h"
cvar_t *r_railWidth;
cvar_t *r_railCoreWidth;
cvar_t *r_railSegmentLength;
cvar_t *r_verbose;
cvar_t *r_znear;
cvar_t *r_inGameVideo;
cvar_t *r_dynamiclight;
cvar_t *r_norefresh;
cvar_t *r_drawentities;
cvar_t *r_drawworld;
cvar_t *r_speeds;
cvar_t *r_fullbright;
cvar_t *r_novis;
cvar_t *r_nocull;
cvar_t *r_facePlaneCull;
cvar_t *r_showcluster;
cvar_t *r_nocurves;
cvar_t* r_fullscreen;
// display refresh rate
cvar_t* r_displayRefresh;
cvar_t *r_lightmap;
cvar_t *r_vertexLight;
cvar_t *r_uiFullScreen;
cvar_t *r_shadows;
cvar_t *r_flares;
cvar_t *r_singleShader;
cvar_t *r_colorMipLevels;
cvar_t *r_picmip;
cvar_t *r_showtris;
cvar_t *r_showsky;
cvar_t *r_shownormals;
cvar_t *r_offsetFactor;
cvar_t *r_offsetUnits;
cvar_t *r_gamma;
cvar_t *r_intensity;
cvar_t *r_lockpvs;
cvar_t *r_noportals;
cvar_t *r_portalOnly;
cvar_t *r_subdivisions;
cvar_t *r_lodCurveError;
// r_overbrightBits->integer, but set to 0 if no hw gamma
// cvar_t *r_overBrightBits;
cvar_t *r_mapOverBrightBits;
cvar_t *r_debugSurface;
cvar_t *r_simpleMipMaps;
cvar_t *r_showImages;
cvar_t *r_ambientScale;
cvar_t *r_directedScale;
cvar_t *r_debugLight;
cvar_t *r_debugSort;
cvar_t *r_printShaders;
cvar_t *r_saveFontData;
cvar_t *r_maxpolys;
cvar_t *r_maxpolyverts;
cvar_t* r_allowResize; // make window resizable
cvar_t* r_mode;
cvar_t* r_loadImgAPI;
void R_Register( void )
{
//
// latched and archived variables
//
r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
ri.Cvar_CheckRange( r_picmip, 0, 8, qtrue );
r_simpleMipMaps = ri.Cvar_Get( "r_simpleMipMaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH );
// r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0);
r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH);
//
// temporary latched variables that can only change over a restart
//
r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_LATCH|CVAR_CHEAT );
r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "1", CVAR_LATCH );
r_intensity = ri.Cvar_Get ("r_intensity", "1.5", CVAR_LATCH | CVAR_ARCHIVE );
r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH );
//
// archived variables that can change at any time
//
r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE|CVAR_CHEAT );
r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE );
r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT );
ri.Cvar_CheckRange( r_znear, 0.001f, 200, qtrue );
r_inGameVideo = ri.Cvar_Get( "r_inGameVideo", "1", CVAR_ARCHIVE );
r_dynamiclight = ri.Cvar_Get( "r_dynamiclight", "1", CVAR_ARCHIVE );
r_gamma = ri.Cvar_Get( "r_gamma", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_facePlaneCull = ri.Cvar_Get ("r_facePlaneCull", "1", CVAR_ARCHIVE );
r_railWidth = ri.Cvar_Get( "r_railWidth", "16", CVAR_ARCHIVE );
r_railCoreWidth = ri.Cvar_Get( "r_railCoreWidth", "6", CVAR_ARCHIVE );
r_railSegmentLength = ri.Cvar_Get( "r_railSegmentLength", "32", CVAR_ARCHIVE );
r_ambientScale = ri.Cvar_Get( "r_ambientScale", "0.6", CVAR_CHEAT );
r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT );
//
// temporary variables that can change at any time
//
r_showImages = ri.Cvar_Get( "r_showImages", "0", CVAR_TEMP );
r_debugLight = ri.Cvar_Get( "r_debuglight", "0", CVAR_TEMP );
r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT );
r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 );
r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 );
r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT );
r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT );
r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 );
r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_TEMP );
r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT);
r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT );
r_nocull = ri.Cvar_Get ("r_nocull", "0", CVAR_CHEAT);
r_novis = ri.Cvar_Get ("r_novis", "0", CVAR_CHEAT);
r_showcluster = ri.Cvar_Get ("r_showcluster", "0", CVAR_CHEAT);
r_speeds = ri.Cvar_Get ("r_speeds", "0", CVAR_CHEAT);
r_verbose = ri.Cvar_Get( "r_verbose", "0", CVAR_CHEAT );
r_debugSurface = ri.Cvar_Get ("r_debugSurface", "0", CVAR_TEMP);
r_showtris = ri.Cvar_Get ("r_showtris", "0", CVAR_TEMP);
r_showsky = ri.Cvar_Get ("r_showsky", "0", CVAR_TEMP);
r_shownormals = ri.Cvar_Get ("r_shownormals", "0", CVAR_TEMP);
r_offsetFactor = ri.Cvar_Get( "r_offsetfactor", "-1", CVAR_CHEAT );
r_offsetUnits = ri.Cvar_Get( "r_offsetunits", "-2", CVAR_CHEAT );
r_lockpvs = ri.Cvar_Get ("r_lockpvs", "0", CVAR_CHEAT);
r_noportals = ri.Cvar_Get ("r_noportals", "0", CVAR_CHEAT);
r_shadows = ri.Cvar_Get( "cg_shadows", "1", 0 );
r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", 600), 0);
r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", 3000), 0);
r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "60", CVAR_LATCH );
ri.Cvar_CheckRange( r_displayRefresh, 0, 200, qtrue );
r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_mode = ri.Cvar_Get( "r_mode", "-2", CVAR_ARCHIVE | CVAR_LATCH );
r_loadImgAPI = ri.Cvar_Get( "r_loadImgAPI", "0", CVAR_ARCHIVE | CVAR_LATCH );
}

98
code/renderervk/tr_cvar.h Normal file
View file

@ -0,0 +1,98 @@
#ifndef TR_CVAR_H_
#define TR_CVAR_H_
#include "../qcommon/q_shared.h"
extern cvar_t *r_railWidth;
extern cvar_t *r_railCoreWidth;
extern cvar_t *r_railSegmentLength;
extern cvar_t *r_verbose; // used for verbose debug spew
extern cvar_t *r_znear; // near Z clip plane
extern cvar_t *r_depthbits; // number of desired depth bits
extern cvar_t *r_inGameVideo; // controls whether in game video should be draw
extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled
extern cvar_t *r_norefresh; // bypasses the ref rendering
extern cvar_t *r_drawentities; // disable/enable entity rendering
extern cvar_t *r_drawworld; // disable/enable world rendering
extern cvar_t *r_speeds; // various levels of information display
extern cvar_t *r_novis; // disable/enable usage of PVS
extern cvar_t *r_nocull;
extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back side test
extern cvar_t *r_nocurves;
extern cvar_t *r_showcluster;
extern cvar_t *r_mode; // video mode
extern cvar_t *r_fullscreen;
extern cvar_t *r_gamma;
extern cvar_t *r_singleShader; // make most world faces use default shader
extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage
extern cvar_t *r_picmip; // controls picmip values
extern cvar_t *r_offsetFactor;
extern cvar_t *r_offsetUnits;
extern cvar_t *r_fullbright; // avoid lightmap pass
extern cvar_t *r_lightmap; // render lightmaps only
extern cvar_t *r_vertexLight; // vertex lighting mode for better performance
extern cvar_t *r_uiFullScreen; // ui is running fullscreen
extern cvar_t *r_showtris; // enables wireframe rendering of the world
extern cvar_t *r_showsky; // forces sky in front of all surfaces
extern cvar_t *r_shownormals; // draws wireframe normals
extern cvar_t *r_clear; // force screen clear every frame
extern cvar_t *r_shadows; // controls shadows: 0 = none, 1 = blur, 2 = stencil, 3 = black planar projection
extern cvar_t *r_intensity;
extern cvar_t *r_lockpvs;
extern cvar_t *r_noportals;
extern cvar_t *r_portalOnly;
extern cvar_t *r_subdivisions;
extern cvar_t *r_lodCurveError;
//extern cvar_t *r_overBrightBits;
extern cvar_t *r_mapOverBrightBits;
extern cvar_t *r_debugSurface;
extern cvar_t *r_simpleMipMaps;
extern cvar_t *r_showImages;
extern cvar_t *r_debugSort;
extern cvar_t *r_printShaders;
extern cvar_t *r_saveFontData;
extern cvar_t *r_maxpolys;
extern cvar_t *r_maxpolyverts;
extern cvar_t *r_ambientScale;
extern cvar_t *r_directedScale;
extern cvar_t *r_debugLight;
extern cvar_t* r_allowResize; // make window resizable
extern cvar_t* r_mode;
extern cvar_t* r_fullscreen;
extern cvar_t* r_displayRefresh;
extern cvar_t* r_loadImgAPI;
void R_Register( void );
#endif

546
code/renderervk/tr_flares.c Normal file
View file

@ -0,0 +1,546 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_flares.c
#include "ref_import.h"
#include "tr_local.h"
extern cvar_t* r_flares;
void RB_SurfaceFlare(srfFlare_t *surf)
{
if (r_flares->integer)
{
ri.Printf(PRINT_DEVELOPER, "I'm so weak, don't know how to implement this.\n");
// RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal);
}
}
/*
=============================================================================
LIGHT FLARES
A light flare is an effect that takes place inside the eye when bright light
sources are visible. The size of the flare relative to the screen is nearly
constant, irrespective of distance, but the intensity should be proportional to the
projected area of the light source.
A surface that has been flagged as having a light flare will calculate the depth
buffer value that its midpoint should have when the surface is added.
After all opaque surfaces have been rendered, the depth buffer is read back for
each flare in view. If the point has not been obscured by a closer surface, the
flare should be drawn.
Surfaces that have a repeated texture should never be flagged as flaring, because
there will only be a single flare added at the midpoint of the polygon.
To prevent abrupt popping, the intensity of the flare is interpolated up and
down as it changes visibility. This involves scene to scene state, unlike almost
all other aspects of the renderer, and is complicated by the fact that a single
frame may have multiple scenes.
RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially
up to five or more times in a frame with 3D status bar icons).
=============================================================================
*/
// flare states maintain visibility over multiple frames for fading
// layers: view, mirror, menu
/*
typedef struct flare_s {
struct flare_s *next; // for active chain
int addedFrame;
qboolean inPortal; // true if in a portal view of the scene
int frameSceneNum;
void *surface;
int fogNum;
int fadeTime;
qboolean visible; // state of last test
float drawIntensity; // may be non 0 even if !visible due to fading
int windowX, windowY;
float eyeZ;
vec3_t origin;
vec3_t color;
} flare_t;
#define MAX_FLARES 256
flare_t r_flareStructs[MAX_FLARES];
flare_t *r_activeFlares, *r_inactiveFlares;
int flareCoeff;
==================
R_SetFlareCoeff
==================
static void R_SetFlareCoeff( void ) {
if(r_flareCoeff->value == 0.0f)
flareCoeff = atof(FLARE_STDCOEFF);
else
flareCoeff = r_flareCoeff->value;
}
*/
/*
==================
R_ClearFlares
==================
void R_ClearFlares( void ) {
int i;
memset( r_flareStructs, 0, sizeof( r_flareStructs ) );
r_activeFlares = NULL;
r_inactiveFlares = NULL;
for ( i = 0 ; i < MAX_FLARES ; i++ ) {
r_flareStructs[i].next = r_inactiveFlares;
r_inactiveFlares = &r_flareStructs[i];
}
R_SetFlareCoeff();
}
*/
/*
==================
RB_AddFlare
This is called at surface tesselation time
==================
void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) {
int i;
flare_t *f;
vec3_t local;
float d = 1;
vec4_t eye, clip, normalized, window;
backEnd.pc.c_flareAdds++;
if(normal && (normal[0] || normal[1] || normal[2]))
{
VectorSubtract( backEnd.viewParms.or.origin, point, local );
FastNormalize1f(local);
d = DotProduct(local, normal);
// If the viewer is behind the flare don't add it.
if(d < 0)
return;
}
// if the point is off the screen, don't bother adding it
// calculate screen coordinates and depth
R_TransformModelToClip( point, backEnd.or.modelMatrix,
backEnd.viewParms.projectionMatrix, eye, clip );
// check to see if the point is completely off screen
for ( i = 0 ; i < 3 ; i++ ) {
if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) {
return;
}
}
R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window );
if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth
|| window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) {
return; // shouldn't happen, since we check the clip[] above, except for FP rounding
}
// see if a flare with a matching surface, scene, and view exists
for ( f = r_activeFlares ; f ; f = f->next ) {
if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum
&& f->inPortal == backEnd.viewParms.isPortal ) {
break;
}
}
// allocate a new one
if (!f ) {
if ( !r_inactiveFlares ) {
// the list is completely full
return;
}
f = r_inactiveFlares;
r_inactiveFlares = r_inactiveFlares->next;
f->next = r_activeFlares;
r_activeFlares = f;
f->surface = surface;
f->frameSceneNum = backEnd.viewParms.frameSceneNum;
f->inPortal = backEnd.viewParms.isPortal;
f->addedFrame = -1;
}
if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) {
f->visible = qfalse;
f->fadeTime = backEnd.refdef.time - 2000;
}
f->addedFrame = backEnd.viewParms.frameCount;
f->fogNum = fogNum;
VectorCopy(point, f->origin);
VectorCopy( color, f->color );
// fade the intensity of the flare down as the
// light surface turns away from the viewer
VectorScale( f->color, d, f->color );
// save info needed to test
f->windowX = backEnd.viewParms.viewportX + window[0];
f->windowY = backEnd.viewParms.viewportY + window[1];
f->eyeZ = eye[2];
}
*/
/*
==================
RB_AddDlightFlares
==================
void RB_AddDlightFlares( void ) {
dlight_t *l;
int i, j, k;
fog_t *fog = NULL;
if ( !r_flares->integer ) {
return;
}
l = backEnd.refdef.dlights;
if(tr.world)
fog = tr.world->fogs;
for (i=0 ; i<backEnd.refdef.num_dlights ; i++, l++) {
if(fog)
{
// find which fog volume the light is in
for ( j = 1 ; j < tr.world->numfogs ; j++ ) {
fog = &tr.world->fogs[j];
for ( k = 0 ; k < 3 ; k++ ) {
if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) {
break;
}
}
if ( k == 3 ) {
break;
}
}
if ( j == tr.world->numfogs ) {
j = 0;
}
}
else
j = 0;
RB_AddFlare( (void *)l, j, l->origin, l->color, NULL );
}
}
*/
/*
===============================================================================
FLARE BACK END
===============================================================================
*/
/*
==================
RB_TestFlare
==================
void RB_TestFlare( flare_t *f ) {
float depth;
qboolean visible;
float fade;
float screenZ;
backEnd.pc.c_flareTests++;
// doing a readpixels is as good as doing a glFinish(), so
// don't bother with another sync
glState.finishCalled = qfalse;
// read back the z buffer contents
qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );
screenZ = backEnd.viewParms.projectionMatrix[14] /
( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] );
visible = ( -f->eyeZ - -screenZ ) < 24;
if ( visible ) {
if ( !f->visible ) {
f->visible = qtrue;
f->fadeTime = backEnd.refdef.time - 1;
}
fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value;
} else {
if ( f->visible ) {
f->visible = qfalse;
f->fadeTime = backEnd.refdef.time - 1;
}
fade = 1.0f - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value;
}
if ( fade < 0 ) {
fade = 0;
}
if ( fade > 1 ) {
fade = 1;
}
f->drawIntensity = fade;
}
*/
/*
* This is an alternative to intensity scaling. It changes the size of the flare on screen instead
* with growing distance. See in the description at the top why this is not the way to go.
// size will change ~ 1/r.
size = backEnd.viewParms.viewportWidth * (r_flareSize->value / (distance * -2.0f));
*/
/*
* As flare sizes stay nearly constant with increasing distance we must decrease the intensity
* to achieve a reasonable visual result. The intensity is ~ (size^2 / distance^2) which can be
* got by considering the ratio of
* (flaresurface on screen) : (Surface of sphere defined by flare origin and distance from flare)
* An important requirement is:
* intensity <= 1 for all distances.
*
* The formula used here to compute the intensity is as follows:
* intensity = flareCoeff * size^2 / (distance + size*sqrt(flareCoeff))^2
* As you can see, the intensity will have a max. of 1 when the distance is 0.
* The coefficient flareCoeff will determine the falloff speed with increasing distance.
void RB_RenderFlare( flare_t *f ) {
float size;
vec3_t color;
int iColor[3];
float distance, intensity, factor;
byte fogFactors[3] = {255, 255, 255};
backEnd.pc.c_flareRenders++;
// We don't want too big values anyways when dividing by distance.
if(f->eyeZ > -1.0f)
distance = 1.0f;
else
distance = -f->eyeZ;
// calculate the flare size..
size = backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0f + 8 / distance );
factor = distance + size * sqrt(flareCoeff);
intensity = flareCoeff * size * size / (factor * factor);
VectorScale(f->color, f->drawIntensity * intensity, color);
// Calculations for fogging
if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs)
{
tess.numVertexes = 1;
VectorCopy(f->origin, tess.xyz[0]);
tess.fogNum = f->fogNum;
RB_CalcModulateColorsByFog(fogFactors);
// We don't need to render the flare if colors are 0 anyways.
if(!(fogFactors[0] || fogFactors[1] || fogFactors[2]))
return;
}
iColor[0] = color[0] * fogFactors[0];
iColor[1] = color[1] * fogFactors[1];
iColor[2] = color[2] * fogFactors[2];
RB_BeginSurface( tr.flareShader, f->fogNum );
// FIXME: use quadstamp?
tess.xyz[tess.numVertexes][0] = f->windowX - size;
tess.xyz[tess.numVertexes][1] = f->windowY - size;
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX - size;
tess.xyz[tess.numVertexes][1] = f->windowY + size;
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX + size;
tess.xyz[tess.numVertexes][1] = f->windowY + size;
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.xyz[tess.numVertexes][0] = f->windowX + size;
tess.xyz[tess.numVertexes][1] = f->windowY - size;
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = iColor[0];
tess.vertexColors[tess.numVertexes][1] = iColor[1];
tess.vertexColors[tess.numVertexes][2] = iColor[2];
tess.vertexColors[tess.numVertexes][3] = 255;
tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 1;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 3;
RB_EndSurface();
}
*/
/*
==================
RB_RenderFlares
Because flares are simulating an occular effect, they should be drawn after
everything (all views) in the entire frame has been drawn.
Because of the way portals use the depth buffer to mark off areas, the
needed information would be lost after each view, so we are forced to draw
flares after each view.
The resulting artifact is that flares in mirrors or portals don't dim properly
when occluded by something in the main view, and portal flares that should
extend past the portal edge will be overwritten.
==================
void RB_RenderFlares (void)
{
flare_t *f;
flare_t **prev;
qboolean draw;
if(r_flareCoeff->modified)
{
R_SetFlareCoeff();
r_flareCoeff->modified = qfalse;
}
// Reset currentEntity to world so that any previously referenced entities
// don't have influence on the rendering of these flares (i.e. RF_ renderer flags).
backEnd.currentEntity = &tr.worldEntity;
backEnd.or = backEnd.viewParms.world;
// RB_AddDlightFlares();
// perform z buffer readback on each flare in this view
draw = qfalse;
prev = &r_activeFlares;
while ( ( f = *prev ) != NULL ) {
// throw out any flares that weren't added last frame
if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) {
*prev = f->next;
f->next = r_inactiveFlares;
r_inactiveFlares = f;
continue;
}
// don't draw any here that aren't from this scene / portal
f->drawIntensity = 0;
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
&& f->inPortal == backEnd.viewParms.isPortal ) {
RB_TestFlare( f );
if ( f->drawIntensity ) {
draw = qtrue;
} else {
// this flare has completely faded out, so remove it from the chain
*prev = f->next;
f->next = r_inactiveFlares;
r_inactiveFlares = f;
continue;
}
}
prev = &f->next;
}
if ( !draw ) {
return; // none visible
}
if ( backEnd.viewParms.isPortal ) {
qglDisable (GL_CLIP_PLANE0);
}
qglPushMatrix();
qglLoadIdentity();
qglMatrixMode( GL_PROJECTION );
qglPushMatrix();
qglLoadIdentity();
qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth,
backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight,
-99999, 99999 );
for ( f = r_activeFlares ; f ; f = f->next ) {
if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum
&& f->inPortal == backEnd.viewParms.isPortal
&& f->drawIntensity ) {
RB_RenderFlare( f );
}
}
qglPopMatrix();
qglMatrixMode( GL_MODELVIEW );
qglPopMatrix();
}
*/

View file

@ -0,0 +1,8 @@
#ifndef TR_FLARE_H_
#define TR_FLARE_H_
void RB_SurfaceFlare(srfFlare_t *surf);
#endif

53
code/renderervk/tr_fog.c Normal file
View file

@ -0,0 +1,53 @@
#include "tr_fog.h"
#include <stdlib.h>
#include <math.h>
#define FOG_TABLE_SIZE 256
static float FogTable[FOG_TABLE_SIZE];
void R_InitFogTable( void )
{
float exp = 0.5;
unsigned int i;
for ( i = 0 ; i < FOG_TABLE_SIZE ; i++ )
{
FogTable[i] = pow ( (float)i/(FOG_TABLE_SIZE-1), exp );
}
}
/*
================
Returns a 0.0 to 1.0 fog density value
This is called for each texel of the fog texture on startup
and for each vertex of transparent shaders in fog dynamically
================
*/
float R_FogFactor( float s, float t )
{
s -= 1.0/512;
if ( s < 0 ) {
return 0;
}
if ( t < 1.0/32 ) {
return 0;
}
if ( t < 31.0/32 ) {
s *= (t - 1.0f/32.0f) / (30.0f/32.0f);
}
// we need to leave a lot of clamp range
s *= 8;
if ( s > 1.0 ) {
s = 1.0;
}
float d = FogTable[ (int)(s * (FOG_TABLE_SIZE-1)) ];
return d;
}

9
code/renderervk/tr_fog.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef TR_FOG_H_
#define TR_FOG_H_
void R_InitFogTable( void );
float R_FogFactor( float s, float t );
#endif

577
code/renderervk/tr_fonts.c Normal file
View file

@ -0,0 +1,577 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_font.c
//
//
// The font system uses FreeType 2.x to render TrueType fonts for use within the game.
// As of this writing ( Nov, 2000 ) Team Arena uses these fonts for all of the ui and
// about 90% of the cgame presentation. A few areas of the CGAME were left uses the old
// fonts since the code is shared with standard Q3A.
//
// If you include this font rendering code in a commercial product you MUST include the
// following somewhere with your product, see www.freetype.org for specifics or changes.
// The Freetype code also uses some hinting techniques that MIGHT infringe on patents
// held by apple so be aware of that also.
//
// As of Q3A 1.25+ and Team Arena, we are shipping the game with the font rendering code
// disabled. This removes any potential patent issues and it keeps us from having to
// distribute an actual TrueTrype font which is 1. expensive to do and 2. seems to require
// an act of god to accomplish.
//
// What we did was pre-render the fonts using FreeType ( which is why we leave the FreeType
// credit in the credits ) and then saved off the glyph data and then hand touched up the
// font bitmaps so they scale a bit better in GL.
//
// There are limitations in the way fonts are saved and reloaded in that it is based on
// point size and not name. So if you pre-render Helvetica in 18 point and Impact in 18 point
// you will end up with a single 18 point data file and image set. Typically you will want to
// choose 3 sizes to best approximate the scaling you will be doing in the ui scripting system
//
// In the UI Scripting code, a scale of 1.0 is equal to a 48 point font. In Team Arena, we
// use three or four scales, most of them exactly equaling the specific rendered size. We
// rendered three sizes in Team Arena, 12, 16, and 20.
//
// To generate new font data you need to go through the following steps.
// 1. delete the fontImage_x_xx.tga files and fontImage_xx.dat files from the fonts path.
// 2. in a ui script, specificy a font, smallFont, and bigFont keyword with font name and
// point size. the original TrueType fonts must exist in fonts at this point.
// 3. run the game, you should see things normally.
// 4. Exit the game and there will be three dat files and at least three tga files. The
// tga's are in 256x256 pages so if it takes three images to render a 24 point font you
// will end up with fontImage_0_24.tga through fontImage_2_24.tga
// 5. In future runs of the game, the system looks for these images and data files when a s
// specific point sized font is rendered and loads them for use.
// 6. Because of the original beta nature of the FreeType code you will probably want to hand
// touch the font bitmaps.
//
// Currently a define in the project turns on or off the FreeType code which is currently
// defined out. To pre-render new fonts you need enable the define ( BUILD_FREETYPE ) and
// uncheck the exclude from build check box in the FreeType2 area of the Renderer project.
#include "tr_local.h"
#include "ref_import.h"
#include "tr_cvar.h"
#ifdef BUILD_FREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_ERRORS_H
#include FT_SYSTEM_H
#include FT_IMAGE_H
#include FT_OUTLINE_H
#define _FLOOR(x) ((x) & -64)
#define _CEIL(x) (((x)+63) & -64)
#define _TRUNC(x) ((x) >> 6)
FT_Library ftLibrary = NULL;
#endif
qhandle_t R_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage);
qhandle_t RE_RegisterShaderNoMip( const char *name );
#define MAX_FONTS 6
static int registeredFontCount = 0;
static fontInfo_t registeredFont[MAX_FONTS];
#ifdef BUILD_FREETYPE
void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) {
*left = _FLOOR( glyph->metrics.horiBearingX );
*right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width );
*width = _TRUNC(*right - *left);
*top = _CEIL( glyph->metrics.horiBearingY );
*bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height );
*height = _TRUNC( *top - *bottom );
*pitch = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 );
}
FT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) {
FT_Bitmap *bit2;
int left, right, width, top, bottom, height, pitch, size;
R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch);
if ( glyph->format == ft_glyph_format_outline ) {
size = pitch*height;
bit2 = ri.Malloc(sizeof(FT_Bitmap));
bit2->width = width;
bit2->rows = height;
bit2->pitch = pitch;
bit2->pixel_mode = ft_pixel_mode_grays;
//bit2->pixel_mode = ft_pixel_mode_mono;
bit2->buffer = ri.Malloc(pitch*height);
bit2->num_grays = 256;
memset( bit2->buffer, 0, size );
FT_Outline_Translate( &glyph->outline, -left, -bottom );
FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 );
glyphOut->height = height;
glyphOut->pitch = pitch;
glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1;
glyphOut->bottom = bottom;
return bit2;
} else {
ri.Printf(PRINT_ALL, "Non-outline fonts are not supported\n");
}
return NULL;
}
void WriteTGA (char *filename, byte *data, int width, int height) {
byte *buffer;
int i, c;
int row;
unsigned char *flip;
unsigned char *src, *dst;
buffer = ri.Malloc(width*height*4 + 18);
memset (buffer, 0, 18);
buffer[2] = 2; // uncompressed type
buffer[12] = width&255;
buffer[13] = width>>8;
buffer[14] = height&255;
buffer[15] = height>>8;
buffer[16] = 32; // pixel size
// swap rgb to bgr
c = 18 + width * height * 4;
for (i=18 ; i<c ; i+=4)
{
buffer[i] = data[i-18+2]; // blue
buffer[i+1] = data[i-18+1]; // green
buffer[i+2] = data[i-18+0]; // red
buffer[i+3] = data[i-18+3]; // alpha
}
// flip upside down
flip = (unsigned char *)ri.Malloc(width*4);
for(row = 0; row < height/2; row++)
{
src = buffer + 18 + row * 4 * width;
dst = buffer + 18 + (height - row - 1) * 4 * width;
memcpy(flip, src, width*4);
memcpy(src, dst, width*4);
memcpy(dst, flip, width*4);
}
ri.Free(flip);
ri.FS_WriteFile(filename, buffer, c);
//f = fopen (filename, "wb");
//fwrite (buffer, 1, c, f);
//fclose (f);
ri.Free (buffer);
}
static glyphInfo_t *RE_ConstructGlyphInfo(unsigned char *imageOut, int *xOut, int *yOut, int *maxHeight, FT_Face face, const unsigned char c, qboolean calcHeight) {
int i;
static glyphInfo_t glyph;
unsigned char *src, *dst;
float scaled_width, scaled_height;
FT_Bitmap *bitmap = NULL;
memset(&glyph, 0, sizeof(glyphInfo_t));
// make sure everything is here
if (face != NULL) {
FT_Load_Glyph(face, FT_Get_Char_Index( face, c), FT_LOAD_DEFAULT );
bitmap = R_RenderGlyph(face->glyph, &glyph);
if (bitmap) {
glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1;
} else {
return &glyph;
}
if (glyph.height > *maxHeight) {
*maxHeight = glyph.height;
}
if (calcHeight) {
ri.Free(bitmap->buffer);
ri.Free(bitmap);
return &glyph;
}
/*
// need to convert to power of 2 sizes so we do not get
// any scaling from the gl upload
for (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1)
;
for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1)
;
*/
scaled_width = glyph.pitch;
scaled_height = glyph.height;
// we need to make sure we fit
if (*xOut + scaled_width + 1 >= 255) {
*xOut = 0;
*yOut += *maxHeight + 1;
}
if (*yOut + *maxHeight + 1 >= 255) {
*yOut = -1;
*xOut = -1;
ri.Free(bitmap->buffer);
ri.Free(bitmap);
return &glyph;
}
src = bitmap->buffer;
dst = imageOut + (*yOut * 256) + *xOut;
if (bitmap->pixel_mode == ft_pixel_mode_mono) {
for (i = 0; i < glyph.height; i++) {
int j;
unsigned char *_src = src;
unsigned char *_dst = dst;
unsigned char mask = 0x80;
unsigned char val = *_src;
for (j = 0; j < glyph.pitch; j++) {
if (mask == 0x80) {
val = *_src++;
}
if (val & mask) {
*_dst = 0xff;
}
mask >>= 1;
if ( mask == 0 ) {
mask = 0x80;
}
_dst++;
}
src += glyph.pitch;
dst += 256;
}
} else {
for (i = 0; i < glyph.height; i++) {
memcpy(dst, src, glyph.pitch);
src += glyph.pitch;
dst += 256;
}
}
// we now have an 8 bit per pixel grey scale bitmap
// that is width wide and pf->ftSize->metrics.y_ppem tall
glyph.imageHeight = scaled_height;
glyph.imageWidth = scaled_width;
glyph.s = (float)*xOut / 256;
glyph.t = (float)*yOut / 256;
glyph.s2 = glyph.s + (float)scaled_width / 256;
glyph.t2 = glyph.t + (float)scaled_height / 256;
*xOut += scaled_width + 1;
ri.Free(bitmap->buffer);
ri.Free(bitmap);
}
return &glyph;
}
#endif
static int fdOffset;
static byte *fdFile;
int readInt( void ) {
int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24);
fdOffset += 4;
return i;
}
typedef union {
byte fred[4];
float ffred;
} poor;
float readFloat( void ) {
poor me;
#if defined Q3_BIG_ENDIAN
me.fred[0] = fdFile[fdOffset+3];
me.fred[1] = fdFile[fdOffset+2];
me.fred[2] = fdFile[fdOffset+1];
me.fred[3] = fdFile[fdOffset+0];
#elif defined Q3_LITTLE_ENDIAN
me.fred[0] = fdFile[fdOffset+0];
me.fred[1] = fdFile[fdOffset+1];
me.fred[2] = fdFile[fdOffset+2];
me.fred[3] = fdFile[fdOffset+3];
#endif
fdOffset += 4;
return me.ffred;
}
void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font)
{
#ifdef BUILD_FREETYPE
FT_Face face;
int j, k, xOut, yOut, lastStart, imageNumber;
int scaledSize, newSize, maxHeight, left;
unsigned char *out, *imageBuff;
glyphInfo_t *glyph;
image_t *image;
qhandle_t h;
float max;
float dpi = 72;
float glyphScale;
#endif
char *faceData;
int i;
char name[1024];
if (!fontName) {
ri.Printf(PRINT_ALL, "RE_RegisterFont: called with empty name\n");
return;
}
if (pointSize <= 0) {
pointSize = 12;
}
if (registeredFontCount >= MAX_FONTS) {
ri.Printf(PRINT_WARNING, "RE_RegisterFont: Too many fonts registered already.\n");
return;
}
snprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize);
for (i = 0; i < registeredFontCount; i++) {
if (Q_stricmp(name, registeredFont[i].name) == 0) {
memcpy(font, &registeredFont[i], sizeof(fontInfo_t));
return;
}
}
int len = ri.FS_ReadFile(name, NULL);
if (len == sizeof(fontInfo_t)) {
ri.FS_ReadFile(name, (void**)&faceData);
fdOffset = 0;
fdFile = (unsigned char*)faceData;
for(i=0; i<GLYPHS_PER_FONT; i++) {
font->glyphs[i].height = readInt();
font->glyphs[i].top = readInt();
font->glyphs[i].bottom = readInt();
font->glyphs[i].pitch = readInt();
font->glyphs[i].xSkip = readInt();
font->glyphs[i].imageWidth = readInt();
font->glyphs[i].imageHeight = readInt();
font->glyphs[i].s = readFloat();
font->glyphs[i].t = readFloat();
font->glyphs[i].s2 = readFloat();
font->glyphs[i].t2 = readFloat();
font->glyphs[i].glyph = readInt();
Q_strncpyz(font->glyphs[i].shaderName, (const char *)&fdFile[fdOffset], sizeof(font->glyphs[i].shaderName));
fdOffset += sizeof(font->glyphs[i].shaderName);
}
font->glyphScale = readFloat();
memcpy(font->name, &fdFile[fdOffset], MAX_QPATH);
// memcpy(font, faceData, sizeof(fontInfo_t));
Q_strncpyz(font->name, name, sizeof(font->name));
for (i = GLYPH_START; i <= GLYPH_END; i++) {
font->glyphs[i].glyph = RE_RegisterShaderNoMip(font->glyphs[i].shaderName);
}
memcpy(&registeredFont[registeredFontCount++], font, sizeof(fontInfo_t));
ri.FS_FreeFile(faceData);
return;
}
#ifndef BUILD_FREETYPE
ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType code not available\n");
#else
if (ftLibrary == NULL) {
ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType not initialized.\n");
return;
}
len = ri.FS_ReadFile(fontName, &faceData);
if (len <= 0) {
ri.Printf(PRINT_WARNING, "RE_RegisterFont: Unable to read font file '%s'\n", fontName);
return;
}
// allocate on the stack first in case we fail
if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) {
ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, unable to allocate new face.\n");
return;
}
if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) {
ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, unable to set face char size.\n");
return;
}
//*font = &registeredFonts[registeredFontCount++];
// make a 256x256 image buffer, once it is full, register it, clean it and keep going
// until all glyphs are rendered
out = ri.Malloc(256*256);
if (out == NULL) {
ri.Printf(PRINT_WARNING, "RE_RegisterFont: ri.Malloc failure during output image creation.\n");
return;
}
memset(out, 0, 256*256);
maxHeight = 0;
for (i = GLYPH_START; i <= GLYPH_END; i++) {
RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue);
}
xOut = 0;
yOut = 0;
i = GLYPH_START;
lastStart = i;
imageNumber = 0;
while ( i <= GLYPH_END + 1 ) {
if ( i == GLYPH_END + 1 ) {
// upload/save current image buffer
xOut = yOut = -1;
} else {
glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse);
}
if (xOut == -1 || yOut == -1) {
// ran out of room
// we need to create an image from the bitmap, set all the handles in the glyphs to this point
//
scaledSize = 256*256;
newSize = scaledSize * 4;
imageBuff = ri.Malloc(newSize);
left = 0;
max = 0;
for ( k = 0; k < (scaledSize) ; k++ ) {
if (max < out[k]) {
max = out[k];
}
}
if (max > 0) {
max = 255/max;
}
for ( k = 0; k < (scaledSize) ; k++ ) {
imageBuff[left++] = 255;
imageBuff[left++] = 255;
imageBuff[left++] = 255;
imageBuff[left++] = ((float)out[k] * max);
}
snprintf (name, sizeof(name), "fonts/fontImage_%i_%i.tga", imageNumber++, pointSize);
if (r_saveFontData->integer) {
WriteTGA(name, imageBuff, 256, 256);
}
image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP);
ri.Printf(PRINT_WARNING, "RE_RegisterFont: ri.Malloc failure during output image creation.\n");
h = R_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse);
for (j = lastStart; j < i; j++) {
font->glyphs[j].glyph = h;
Q_strncpyz(font->glyphs[j].shaderName, name, sizeof(font->glyphs[j].shaderName));
}
lastStart = i;
memset(out, 0, 256*256);
xOut = 0;
yOut = 0;
ri.Free(imageBuff);
if ( i == GLYPH_END + 1 )
i++;
} else {
memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t));
i++;
}
}
// change the scale to be relative to 1 based on 72 dpi ( so dpi of 144 means a scale of .5 )
glyphScale = 72.0f / dpi;
// we also need to adjust the scale based on point size relative to 48 points as the ui scaling is based on a 48 point font
glyphScale *= 48.0f / pointSize;
registeredFont[registeredFontCount].glyphScale = glyphScale;
font->glyphScale = glyphScale;
memcpy(&registeredFont[registeredFontCount++], font, sizeof(fontInfo_t));
if (r_saveFontData->integer) {
ri.FS_WriteFile(va("fonts/fontImage_%i.dat", pointSize), font, sizeof(fontInfo_t));
}
ri.Free(out);
ri.FS_FreeFile(faceData);
#endif
}
void R_InitFreeType(void)
{
#ifdef BUILD_FREETYPE
if (FT_Init_FreeType( &ftLibrary )) {
ri.Printf(PRINT_WARNING, "R_InitFreeType: Unable to initialize FreeType.\n");
}
#endif
registeredFontCount = 0;
r_saveFontData = ri.Cvar_Get( "r_saveFontData", "0", 0 );
}
void R_DoneFreeType(void) {
#ifdef BUILD_FREETYPE
if (ftLibrary) {
FT_Done_FreeType( ftLibrary );
ftLibrary = NULL;
}
#endif
registeredFontCount = 0;
}

View file

@ -0,0 +1,4 @@
#include "tr_globals.h"
trGlobals_t tr;

View file

@ -0,0 +1,101 @@
#ifndef TR_GLOBALS_H_
#define TR_GLOBALS_H_
#include "tr_local.h"
#include "tr_model.h"
// 12 bits, see QSORT_SHADERNUM_SHIFT
#define MAX_SHADERS 16384
/*
** trGlobals_t
**
** Most renderer globals are defined here.
** backend functions should never modify any of these fields,
** but may read fields that aren't dynamically modified
** by the frontend.
*/
typedef struct {
qboolean registered; // cleared at shutdown, set at beginRegistration
int visCount; // incremented every time a new vis cluster is entered
int viewCount; // incremented every view (twice a scene if portaled)
// and every R_MarkFragments call
qboolean worldMapLoaded;
world_t *world;
const unsigned char *externalVisData; // from RE_SetWorldVisData, shared with CM_Load
image_t *defaultImage;
image_t *scratchImage[32];
image_t *fogImage;
image_t *dlightImage; // inverse-quare highlight for projective adding
image_t *whiteImage; // full of 0xff
image_t *identityLightImage; // full of tr.identityLightByte
shader_t *defaultShader;
shader_t *cinematicShader;
shader_t *shadowShader;
shader_t *projectionShadowShader;
int numLightmaps;
image_t *lightmaps[MAX_LIGHTMAPS];
trRefEntity_t *currentEntity;
trRefEntity_t worldEntity; // point currentEntity at this when rendering world
int currentEntityNum;
int shiftedEntityNum; // currentEntityNum << QSORT_ENTITYNUM_SHIFT
model_t *currentModel;
viewParms_t viewParms;
float identityLight; // 1.0 / ( 1 << overbrightBits )
int identityLightByte; // identityLight * 255
orientationr_t or; // for current entity
trRefdef_t refdef;
int viewCluster;
vec3_t sunLight; // from the sky shader for this level
vec3_t sunDirection;
frontEndCounters_t pc;
int frontEndMsec; // not in pc due to clearing issue
//
// put large tables at the end, so most elements will be
// within the +/32K indexed range on risc processors
//
model_t *models[MAX_MOD_KNOWN];
int numModels;
int numImages;
image_t * images[MAX_DRAWIMAGES];
// shader indexes from other modules will be looked up in tr.shaders[]
// shader indexes from drawsurfs will be looked up in sortedShaders[]
// lower indexed sortedShaders must be rendered first (opaque surfaces before translucent)
int numShaders;
shader_t *shaders[MAX_SHADERS];
shader_t *sortedShaders[MAX_SHADERS];
int numSkins;
skin_t *skins[MAX_SKINS];
float sinTable[FUNCTABLE_SIZE];
float squareTable[FUNCTABLE_SIZE];
float triangleTable[FUNCTABLE_SIZE];
float sawToothTable[FUNCTABLE_SIZE];
float inverseSawToothTable[FUNCTABLE_SIZE];
} trGlobals_t;
extern trGlobals_t tr;
#endif

310
code/renderervk/tr_image.c Normal file
View file

@ -0,0 +1,310 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
/*
============================================================================
SKINS
============================================================================
*/
#include "tr_local.h"
#include "tr_globals.h"
#include "ref_import.h"
#include "tr_shader.h"
/*
==================
CommaParse
This is unfortunate, but the skin files aren't
compatable with our normal parsing rules.
==================
*/
static char *CommaParse( char **data_p )
{
int c = 0, len;
char *data;
static char com_token[MAX_TOKEN_CHARS];
data = *data_p;
len = 0;
com_token[0] = 0;
// make sure incoming data is valid
if ( !data ) {
*data_p = NULL;
return com_token;
}
while ( 1 ) {
// skip whitespace
while( (c = *data) <= ' ') {
if( !c ) {
break;
}
data++;
}
c = *data;
// skip double slash comments
if ( c == '/' && data[1] == '/' )
{
while (*data && *data != '\n')
data++;
}
// skip /* */ comments
else if ( c=='/' && data[1] == '*' )
{
while ( *data && ( *data != '*' || data[1] != '/' ) )
{
data++;
}
if ( *data )
{
data += 2;
}
}
else
{
break;
}
}
if ( c == 0 ) {
return "";
}
// handle quoted strings
if (c == '\"')
{
data++;
while (1)
{
c = *data++;
if (c=='\"' || !c)
{
com_token[len] = 0;
*data_p = ( char * ) data;
return com_token;
}
if (len < MAX_TOKEN_CHARS)
{
com_token[len] = c;
len++;
}
}
}
// parse a regular word
do
{
if (len < MAX_TOKEN_CHARS)
{
com_token[len] = c;
len++;
}
data++;
c = *data;
} while (c>32 && c != ',' );
if (len == MAX_TOKEN_CHARS)
{
ri.Printf (PRINT_ALL, "Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
len = 0;
}
com_token[len] = 0;
*data_p = ( char * ) data;
return com_token;
}
qhandle_t RE_RegisterSkin( const char *name )
{
skinSurface_t parseSurfaces[MAX_SKIN_SURFACES];
qhandle_t hSkin;
skin_t *skin;
skinSurface_t *surf;
char *text, *text_p;
char *token;
char surfName[MAX_QPATH];
if ( !name || !name[0] ) {
ri.Printf(PRINT_ALL, "Empty name passed to RE_RegisterSkin\n" );
return 0;
}
if ( (int)strlen( name ) >= MAX_QPATH ) {
ri.Printf(PRINT_ALL, "Skin name exceeds MAX_QPATH\n" );
return 0;
}
// see if the skin is already loaded
for ( hSkin = 1; hSkin < tr.numSkins ; hSkin++ ) {
skin = tr.skins[hSkin];
if ( !Q_stricmp( skin->name, name ) ) {
if( skin->numSurfaces == 0 ) {
return 0; // default skin
}
return hSkin;
}
}
// allocate a new skin
if ( tr.numSkins == MAX_SKINS ) {
ri.Printf( PRINT_WARNING, "WARNING: RE_RegisterSkin( '%s' ) MAX_SKINS hit\n", name );
return 0;
}
tr.numSkins++;
skin = (skin_t*) ri.Hunk_Alloc( sizeof( skin_t ), h_low );
tr.skins[hSkin] = skin;
Q_strncpyz( skin->name, name, sizeof( skin->name ) );
skin->numSurfaces = 0;
// If not a .skin file, load as a single shader
if ( strcmp( name + (int)strlen( name ) - 5, ".skin" ) ) {
skin->numSurfaces = 1;
skin->pSurfaces = (skinSurface_t *) ri.Hunk_Alloc( sizeof(skinSurface_t), h_low );
skin->pSurfaces[0].shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
return hSkin;
}
// load and parse the skin file
ri.FS_ReadFile( name, (void**)&text );
if ( !text ) {
return 0;
}
text_p = text;
while ( text_p && *text_p ) {
// get surface name
token = CommaParse( &text_p );
Q_strncpyz( surfName, token, sizeof( surfName ) );
if ( !token[0] ) {
break;
}
// lowercase the surface name so skin compares are faster
Q_strlwr( surfName );
if ( *text_p == ',' ) {
text_p++;
}
if ( strstr( token, "tag_" ) ) {
continue;
}
// parse the shader name
token = CommaParse( &text_p );
// surf = skin->surfaces[ skin->numSurfaces ] = (skinSurface_t*) ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
surf = &parseSurfaces[skin->numSurfaces];
Q_strncpyz( surf->name, surfName, sizeof( surf->name ) );
surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue );
skin->numSurfaces++;
}
ri.FS_FreeFile( text );
// never let a skin have 0 shaders
if ( skin->numSurfaces == 0 ) {
return 0; // use default skin
}
// copy surfaces to skin
skin->pSurfaces = ri.Hunk_Alloc( skin->numSurfaces * sizeof( skinSurface_t ), h_low );
memcpy( skin->pSurfaces, parseSurfaces, skin->numSurfaces * sizeof( skinSurface_t ) );
return hSkin;
}
/*
===============
R_InitSkins
===============
*/
void R_InitSkins( void )
{
skin_t *skin;
tr.numSkins = 1;
// make the default skin have all default shaders
skin = tr.skins[0] = (skin_t*) ri.Hunk_Alloc( sizeof( skin_t ), h_low );
Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name ) );
skin->numSurfaces = 1;
// skin->surfaces[0] = (skinSurface_t*) ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low );
// skin->surfaces[0]->shader = tr.defaultShader;
skin->pSurfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low );
skin->pSurfaces[0].shader = tr.defaultShader;
}
/*
===============
R_GetSkinByHandle
===============
*/
skin_t* R_GetSkinByHandle( qhandle_t hSkin )
{
if ( hSkin < 1 || hSkin >= tr.numSkins ) {
return tr.skins[0];
}
return tr.skins[ hSkin ];
}
/*
===============
R_SkinList_f
===============
*/
void R_SkinList_f( void )
{
int i, j;
skin_t *skin;
ri.Printf (PRINT_ALL, "------------------\n");
for ( i = 0 ; i < tr.numSkins ; i++ ) {
skin = tr.skins[i];
// ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name );
ri.Printf( PRINT_ALL, "%3i:%s (%d surfaces)\n", i, skin->name, skin->numSurfaces );
for ( j = 0 ; j < skin->numSurfaces ; j++ ) {
ri.Printf( PRINT_ALL, " %s = %s\n",
skin->pSurfaces[j].name, skin->pSurfaces[j].shader->name );
}
}
ri.Printf (PRINT_ALL, "------------------\n");
}

View file

@ -0,0 +1,37 @@
#ifndef TR_IMAGE_H_
#define TR_IMAGE_H_
#include "VKimpl.h"
typedef struct image_s {
char imgName[MAX_QPATH]; // game path, including extension
uint32_t width, height; // source image
uint32_t uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE
uint32_t index;
VkImage handle;
// To use any VkImage, including those in the swap chain, int the render pipeline
// we have to create a VkImageView object. An image view is quite literally a
// view into image. It describe how to access the image and witch part of the
// image to access, if it should be treated as a 2D texture depth texture without
// any mipmapping levels.
VkImageView view;
// Descriptor set that contains single descriptor used to access the given image.
// It is updated only once during image initialization.
VkDescriptorSet descriptor_set;
int wrapClampMode; // GL_CLAMP or GL_REPEAT, for vulkan
VkBool32 mipmap; // for vulkan
uint32_t mipLevels; // gl texture binding
VkBool32 allowPicmip; // for vulkan
VkBool32 isLightmap;
struct image_s* next;
} image_t;
#endif

226
code/renderervk/tr_init.c Normal file
View file

@ -0,0 +1,226 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_init.c -- functions that are not called every frame
#include "tr_local.h"
#include "tr_globals.h"
#include "tr_model.h"
#include "tr_cvar.h"
#include "vk_init.h"
#include "vk_screenshot.h"
#include "vk_shade_geometry.h"
#include "vk_pipelines.h"
#include "vk_image.h"
#include "tr_fog.h"
#include "tr_backend.h"
#include "glConfig.h"
#include "ref_import.h"
extern void RE_ClearScene( void );
void R_Init( void )
{
int i;
ri.Printf( PRINT_ALL, "----- R_Init -----\n" );
// clear all our internal state
memset( &tr, 0, sizeof( tr ) );
memset( &tess, 0, sizeof( tess ) );
R_ClearBackendState();
if ( (intptr_t)tess.xyz & 15 ) {
ri.Printf( PRINT_ALL, "WARNING: tess.xyz not 16 byte aligned\n" );
}
//
// init function tables
//
for ( i = 0; i < FUNCTABLE_SIZE; i++ )
{
tr.sinTable[i] = sin( DEG2RAD( i * 360.0f / ( ( float ) ( FUNCTABLE_SIZE - 1 ) ) ) );
tr.squareTable[i] = ( i < FUNCTABLE_SIZE/2 ) ? 1.0f : -1.0f;
tr.sawToothTable[i] = (float)i / FUNCTABLE_SIZE;
tr.inverseSawToothTable[i] = 1.0f - tr.sawToothTable[i];
if ( i < FUNCTABLE_SIZE / 2 )
{
if ( i < FUNCTABLE_SIZE / 4 )
{
tr.triangleTable[i] = ( float ) i / ( FUNCTABLE_SIZE / 4 );
}
else
{
tr.triangleTable[i] = 1.0f - tr.triangleTable[i-FUNCTABLE_SIZE / 4];
}
}
else
{
tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2];
}
}
R_InitDisplayResolution();
R_InitFogTable();
R_NoiseInit();
R_Register();
// make sure all the commands added here are also
// removed in R_Shutdown
ri.Cmd_AddCommand( "displayResoList", R_DisplayResolutionList_f );
ri.Cmd_AddCommand( "modellist", R_Modellist_f );
ri.Cmd_AddCommand( "screenshotJPEG", R_ScreenShotJPEG_f );
ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f );
ri.Cmd_AddCommand( "skinlist", R_SkinList_f );
ri.Cmd_AddCommand( "vkinfo", vulkanInfo_f );
ri.Cmd_AddCommand( "minimize", vk_minimizeWindow );
ri.Cmd_AddCommand( "pipelineList", R_PipelineList_f );
ri.Cmd_AddCommand( "gpuMem", gpuMemUsageInfo_f );
ri.Cmd_AddCommand( "printOR", R_PrintBackEnd_OR_f );
R_InitScene();
R_glConfigInit();
// VULKAN
if ( !isVKinitialied() )
{
vk_initialize();
// print info
vulkanInfo_f();
}
R_InitImages();
R_InitShaders();
R_InitSkins();
R_ModelInit();
R_InitFreeType();
ri.Printf( PRINT_ALL, "----- R_Init finished -----\n" );
}
void RE_Shutdown( qboolean destroyWindow )
{
ri.Printf( PRINT_ALL, "\nRE_Shutdown( %i )\n", destroyWindow );
ri.Cmd_RemoveCommand("displayResoList");
ri.Cmd_RemoveCommand("modellist");
ri.Cmd_RemoveCommand("screenshotJPEG");
ri.Cmd_RemoveCommand("screenshot");
ri.Cmd_RemoveCommand("shaderlist");
ri.Cmd_RemoveCommand("skinlist");
ri.Cmd_RemoveCommand("minimize");
ri.Cmd_RemoveCommand("vkinfo");
ri.Cmd_RemoveCommand("pipelineList");
ri.Cmd_RemoveCommand("gpuMem");
ri.Cmd_RemoveCommand("printOR");
R_DoneFreeType();
// VULKAN
// Releases vulkan resources allocated during program execution.
// This effectively puts vulkan subsystem into initial state
// (the state we have after vk_initialize call).
// contains vulkan resources/state, reinitialized on a map change.
vk_destroyShaderStagePipeline();
vk_resetGeometryBuffer();
if ( tr.registered )
{
vk_destroyImageRes();
tr.registered = qfalse;
}
if (destroyWindow)
{
vk_shutdown();
vk_destroyWindow();
// It is cleared not for renderer_vulkan,
// but fot rendergl1, renderergl2 to create the window
R_glConfigClear();
}
}
void RE_BeginRegistration(glconfig_t * pGlCfg)
{
R_Init();
R_GetGlConfig(pGlCfg);
tr.viewCluster = -1; // force markleafs to regenerate
RE_ClearScene();
tr.registered = qtrue;
ri.Printf(PRINT_ALL, "RE_BeginRegistration finished.\n");
}
/*
=============
RE_EndRegistration
Touch all images to make sure they are resident
=============
*/
void RE_EndRegistration( void )
{
if ( tr.registered ) {
R_IssueRenderCommands( qfalse );
}
}

396
code/renderervk/tr_light.c Normal file
View file

@ -0,0 +1,396 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_light.c
#include "tr_local.h"
#include "tr_globals.h"
#include "ref_import.h"
#include "tr_cvar.h"
#include "tr_light.h"
#define DLIGHT_AT_RADIUS 16
// at the edge of a dlight's influence, this amount of light will be added
#define DLIGHT_MINIMUM_RADIUS 16
// never calculate a range less than this to prevent huge light numbers
/*
===============
R_TransformDlights
Transforms the origins of an array of dlights.
Used by both the front end (for DlightBmodel) and
the back end (before doing the lighting calculation)
===============
*/
void R_TransformDlights( int count, dlight_t *dl, const orientationr_t * const or)
{
int i;
for ( i = 0 ; i < count ; i++, dl++ )
{
vec3_t temp;
VectorSubtract( dl->origin, or->origin, temp );
dl->transformed[0] = DotProduct( temp, or->axis[0] );
dl->transformed[1] = DotProduct( temp, or->axis[1] );
dl->transformed[2] = DotProduct( temp, or->axis[2] );
}
}
/*
=============
R_DlightBmodel
Determine which dynamic lights may effect this bmodel
=============
*/
void R_DlightBmodel( bmodel_t *bmodel ) {
int i, j;
dlight_t *dl;
int mask;
msurface_t *surf;
// transform all the lights
R_TransformDlights( tr.refdef.num_dlights, tr.refdef.dlights, &tr.or );
mask = 0;
for ( i=0 ; i<tr.refdef.num_dlights ; i++ ) {
dl = &tr.refdef.dlights[i];
// see if the point is close enough to the bounds to matter
for ( j = 0 ; j < 3 ; j++ ) {
if ( dl->transformed[j] - bmodel->bounds[1][j] > dl->radius ) {
break;
}
if ( bmodel->bounds[0][j] - dl->transformed[j] > dl->radius ) {
break;
}
}
if ( j < 3 ) {
continue;
}
// we need to check this light
mask |= 1 << i;
}
tr.currentEntity->needDlights = (qboolean) (mask != 0);
// set the dlight bits in all the surfaces
for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
surf = bmodel->firstSurface + i;
if ( *surf->data == SF_FACE ) {
((srfSurfaceFace_t *)surf->data)->dlightBits = mask;
} else if ( *surf->data == SF_GRID ) {
((srfGridMesh_t *)surf->data)->dlightBits = mask;
} else if ( *surf->data == SF_TRIANGLES ) {
((srfTriangles_t *)surf->data)->dlightBits = mask;
}
}
}
/*
=============================================================================
LIGHT SAMPLING
=============================================================================
*/
/*
=================
R_SetupEntityLightingGrid
=================
*/
static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
vec3_t lightOrigin;
int pos[3];
int i, j;
byte *gridData;
float frac[3];
int gridStep[3];
vec3_t direction;
float totalFactor;
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
// seperate lightOrigins are needed so an object that is
// sinking into the ground can still be lit, and so
// multi-part models can be lit identically
VectorCopy( ent->e.lightingOrigin, lightOrigin );
} else {
VectorCopy( ent->e.origin, lightOrigin );
}
VectorSubtract( lightOrigin, tr.world->lightGridOrigin, lightOrigin );
for ( i = 0 ; i < 3 ; i++ ) {
float v;
v = lightOrigin[i]*tr.world->lightGridInverseSize[i];
pos[i] = floor( v );
frac[i] = v - pos[i];
if ( pos[i] < 0 ) {
pos[i] = 0;
} else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
pos[i] = tr.world->lightGridBounds[i] - 1;
}
}
VectorClear( ent->ambientLight );
VectorClear( ent->directedLight );
VectorClear( direction );
assert( tr.world->lightGridData ); // bk010103 - NULL with -nolight maps
// trilerp the light value
gridStep[0] = 8;
gridStep[1] = 8 * tr.world->lightGridBounds[0];
gridStep[2] = 8 * tr.world->lightGridBounds[0] * tr.world->lightGridBounds[1];
gridData = tr.world->lightGridData + pos[0] * gridStep[0]
+ pos[1] * gridStep[1] + pos[2] * gridStep[2];
totalFactor = 0;
for ( i = 0 ; i < 8 ; i++ ) {
float factor;
byte *data;
int lat, lng;
vec3_t normal;
#if idppc
float d0, d1, d2, d3, d4, d5;
#endif
factor = 1.0;
data = gridData;
for ( j = 0 ; j < 3 ; j++ ) {
if ( i & (1<<j) ) {
factor *= frac[j];
data += gridStep[j];
} else {
factor *= (1.0f - frac[j]);
}
}
if ( !(data[0]+data[1]+data[2]) ) {
continue; // ignore samples in walls
}
totalFactor += factor;
#if idppc
d0 = data[0]; d1 = data[1]; d2 = data[2];
d3 = data[3]; d4 = data[4]; d5 = data[5];
ent->ambientLight[0] += factor * d0;
ent->ambientLight[1] += factor * d1;
ent->ambientLight[2] += factor * d2;
ent->directedLight[0] += factor * d3;
ent->directedLight[1] += factor * d4;
ent->directedLight[2] += factor * d5;
#else
ent->ambientLight[0] += factor * data[0];
ent->ambientLight[1] += factor * data[1];
ent->ambientLight[2] += factor * data[2];
ent->directedLight[0] += factor * data[3];
ent->directedLight[1] += factor * data[4];
ent->directedLight[2] += factor * data[5];
#endif
lat = data[7];
lng = data[6];
lat *= (FUNCTABLE_SIZE/256);
lng *= (FUNCTABLE_SIZE/256);
// decode X as cos( lat ) * sin( long )
// decode Y as sin( lat ) * sin( long )
// decode Z as cos( long )
normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng];
normal[1] = tr.sinTable[lat] * tr.sinTable[lng];
normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK];
VectorMA( direction, factor, normal, direction );
}
if ( totalFactor > 0 && totalFactor < 0.99 ) {
totalFactor = 1.0f / totalFactor;
VectorScale( ent->ambientLight, totalFactor, ent->ambientLight );
VectorScale( ent->directedLight, totalFactor, ent->directedLight );
}
VectorScale( ent->ambientLight, r_ambientScale->value, ent->ambientLight );
VectorScale( ent->directedLight, r_directedScale->value, ent->directedLight );
VectorNormalize2( direction, ent->lightDir );
}
/*
===============
LogLight
===============
*/
static void LogLight( trRefEntity_t *ent ) {
int max1, max2;
if ( !(ent->e.renderfx & RF_FIRST_PERSON ) ) {
return;
}
max1 = ent->ambientLight[0];
if ( ent->ambientLight[1] > max1 ) {
max1 = ent->ambientLight[1];
} else if ( ent->ambientLight[2] > max1 ) {
max1 = ent->ambientLight[2];
}
max2 = ent->directedLight[0];
if ( ent->directedLight[1] > max2 ) {
max2 = ent->directedLight[1];
} else if ( ent->directedLight[2] > max2 ) {
max2 = ent->directedLight[2];
}
ri.Printf( PRINT_ALL, "amb:%i dir:%i\n", max1, max2 );
}
/*
=================
R_SetupEntityLighting
Calculates all the lighting values that will be used
by the Calc_* functions
=================
*/
void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) {
int i;
dlight_t *dl;
float power;
vec3_t dir;
float d;
vec3_t lightDir;
vec3_t lightOrigin;
// lighting calculations
if ( ent->lightingCalculated ) {
return;
}
ent->lightingCalculated = qtrue;
//
// trace a sample point down to find ambient light
//
if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) {
// seperate lightOrigins are needed so an object that is
// sinking into the ground can still be lit, and so
// multi-part models can be lit identically
VectorCopy( ent->e.lightingOrigin, lightOrigin );
} else {
VectorCopy( ent->e.origin, lightOrigin );
}
// if NOWORLDMODEL, only use dynamic lights (menu system, etc)
if ( !(refdef->rd.rdflags & RDF_NOWORLDMODEL )
&& tr.world->lightGridData ) {
R_SetupEntityLightingGrid( ent );
} else {
ent->ambientLight[0] = ent->ambientLight[1] =
ent->ambientLight[2] = tr.identityLight * 150;
ent->directedLight[0] = ent->directedLight[1] =
ent->directedLight[2] = tr.identityLight * 150;
VectorCopy( tr.sunDirection, ent->lightDir );
}
// bonus items and view weapons have a fixed minimum add
if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) {
// give everything a minimum light add
ent->ambientLight[0] += tr.identityLight * 32;
ent->ambientLight[1] += tr.identityLight * 32;
ent->ambientLight[2] += tr.identityLight * 32;
}
//
// modify the light by dynamic lights
//
d = VectorLength( ent->directedLight );
VectorScale( ent->lightDir, d, lightDir );
for ( i = 0 ; i < refdef->num_dlights ; i++ ) {
dl = &refdef->dlights[i];
VectorSubtract( dl->origin, lightOrigin, dir );
d = VectorNormalize( dir );
power = DLIGHT_AT_RADIUS * ( dl->radius * dl->radius );
if ( d < DLIGHT_MINIMUM_RADIUS ) {
d = DLIGHT_MINIMUM_RADIUS;
}
d = power / ( d * d );
VectorMA( ent->directedLight, d, dl->color, ent->directedLight );
VectorMA( lightDir, d, dir, lightDir );
}
// clamp ambient
for ( i = 0 ; i < 3 ; i++ ) {
if ( ent->ambientLight[i] > tr.identityLightByte ) {
ent->ambientLight[i] = tr.identityLightByte;
}
}
if ( r_debugLight->integer ) {
LogLight( ent );
}
// save out the byte packet version
ent->ambientLightRGBA[0] = (unsigned char)( ent->ambientLight[0] );
ent->ambientLightRGBA[1] = (unsigned char)( ent->ambientLight[1] );
ent->ambientLightRGBA[2] = (unsigned char)( ent->ambientLight[2] );
ent->ambientLightRGBA[3] = 0xff;
// transform the direction to local space
VectorNormalize( lightDir );
ent->lightDir[0] = DotProduct( lightDir, ent->e.axis[0] );
ent->lightDir[1] = DotProduct( lightDir, ent->e.axis[1] );
ent->lightDir[2] = DotProduct( lightDir, ent->e.axis[2] );
}
int RE_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir )
{
trRefEntity_t ent;
// bk010103 - this segfaults with -nolight maps
if ( tr.world->lightGridData == NULL )
return qfalse;
memset(&ent, 0, sizeof(ent));
VectorCopy( point, ent.e.origin );
R_SetupEntityLightingGrid( &ent );
VectorCopy(ent.ambientLight, ambientLight);
VectorCopy(ent.directedLight, directedLight);
VectorCopy(ent.lightDir, lightDir);
return qtrue;
}

View file

@ -0,0 +1,23 @@
#ifndef TR_LIGHT_H_
#define TR_LIGHT_H_
// can't be increased without changing bit packing for drawsurfs
typedef struct dlight_s {
float origin[3];
float color[3]; // range from 0.0 to 1.0, should be color normalized
float transformed[3]; // origin in local coordinate system
float radius;
int additive; // texture detail is lost tho when the lightmap is dark
} dlight_t;
void R_DlightBmodel( bmodel_t *bmodel );
void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent );
void R_TransformDlights( int count, dlight_t *dl, const orientationr_t * const or );
#endif

1021
code/renderervk/tr_local.h Normal file

File diff suppressed because it is too large Load diff

1311
code/renderervk/tr_main.c Normal file

File diff suppressed because it is too large Load diff

441
code/renderervk/tr_marks.c Normal file
View file

@ -0,0 +1,441 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_marks.c -- polygon projection on the world polygons
#include "tr_local.h"
#include "tr_globals.h"
#include "matrix_multiplication.h"
#define MAX_VERTS_ON_POLY 64
#define MARKER_OFFSET 0 // 1
/*
=============
R_ChopPolyBehindPlane
Out must have space for two more vertexes than in
=============
*/
#define SIDE_FRONT 0
#define SIDE_BACK 1
#define SIDE_ON 2
static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
vec3_t normal, vec_t dist, vec_t epsilon) {
float dists[MAX_VERTS_ON_POLY+4];
int sides[MAX_VERTS_ON_POLY+4];
int counts[3];
float dot;
int i, j;
float *p1, *p2, *clip;
float d;
// don't clip if it might overflow
if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
*numOutPoints = 0;
return;
}
counts[0] = counts[1] = counts[2] = 0;
// determine sides for each point
for ( i = 0 ; i < numInPoints ; i++ ) {
dot = DotProduct( inPoints[i], normal );
dot -= dist;
dists[i] = dot;
if ( dot > epsilon ) {
sides[i] = SIDE_FRONT;
} else if ( dot < -epsilon ) {
sides[i] = SIDE_BACK;
} else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
sides[i] = sides[0];
dists[i] = dists[0];
*numOutPoints = 0;
if ( !counts[0] ) {
return;
}
if ( !counts[1] ) {
*numOutPoints = numInPoints;
memcpy( outPoints, inPoints, numInPoints * sizeof(vec3_t) );
return;
}
for ( i = 0 ; i < numInPoints ; i++ ) {
p1 = inPoints[i];
clip = outPoints[ *numOutPoints ];
if ( sides[i] == SIDE_ON ) {
VectorCopy( p1, clip );
(*numOutPoints)++;
continue;
}
if ( sides[i] == SIDE_FRONT ) {
VectorCopy( p1, clip );
(*numOutPoints)++;
clip = outPoints[ *numOutPoints ];
}
if ( sides[i+1] == SIDE_ON || sides[i+1] == sides[i] ) {
continue;
}
// generate a split point
p2 = inPoints[ (i+1) % numInPoints ];
d = dists[i] - dists[i+1];
if ( d == 0 ) {
dot = 0;
} else {
dot = dists[i] / d;
}
// clip xyz
for (j=0 ; j<3 ; j++) {
clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
}
(*numOutPoints)++;
}
}
/*
=================
R_BoxSurfaces_r
=================
*/
void R_BoxSurfaces_r(mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir) {
int s, c;
msurface_t *surf, **mark;
// do the tail recursion in a loop
while ( node->contents == -1 ) {
s = BoxOnPlaneSide( mins, maxs, node->plane );
if (s == 1) {
node = node->children[0];
} else if (s == 2) {
node = node->children[1];
} else {
R_BoxSurfaces_r(node->children[0], mins, maxs, list, listsize, listlength, dir);
node = node->children[1];
}
}
// add the individual surfaces
mark = node->firstmarksurface;
c = node->nummarksurfaces;
while (c--) {
//
if (*listlength >= listsize) break;
//
surf = *mark;
// check if the surface has NOIMPACT or NOMARKS set
if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
|| ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
surf->viewCount = tr.viewCount;
}
// extra check for surfaces to avoid list overflows
else if (*(surf->data) == SF_FACE) {
// the face plane should go through the box
s = BoxOnPlaneSide( mins, maxs, &(( srfSurfaceFace_t * ) surf->data)->plane );
if (s == 1 || s == 2) {
surf->viewCount = tr.viewCount;
} else if (DotProduct((( srfSurfaceFace_t * ) surf->data)->plane.normal, dir) > -0.5) {
// don't add faces that make sharp angles with the projection direction
surf->viewCount = tr.viewCount;
}
}
else if (*(surfaceType_t *) (surf->data) != SF_GRID) surf->viewCount = tr.viewCount;
// check the viewCount because the surface may have
// already been added if it spans multiple leafs
if (surf->viewCount != tr.viewCount) {
surf->viewCount = tr.viewCount;
list[*listlength] = (surfaceType_t *) surf->data;
(*listlength)++;
}
mark++;
}
}
/*
=================
R_AddMarkFragments
=================
*/
void R_AddMarkFragments(int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
int numPlanes, vec3_t *normals, float *dists,
int maxPoints, vec3_t pointBuffer,
int maxFragments, markFragment_t *fragmentBuffer,
int *returnedPoints, int *returnedFragments,
vec3_t mins, vec3_t maxs) {
int pingPong, i;
markFragment_t *mf;
// chop the surface by all the bounding planes of the to be projected polygon
pingPong = 0;
for ( i = 0 ; i < numPlanes ; i++ ) {
R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
&numClipPoints, clipPoints[!pingPong],
normals[i], dists[i], 0.5 );
pingPong ^= 1;
if ( numClipPoints == 0 ) {
break;
}
}
// completely clipped away?
if ( numClipPoints == 0 ) {
return;
}
// add this fragment to the returned list
if ( numClipPoints + (*returnedPoints) > maxPoints ) {
return; // not enough space for this polygon
}
/*
// all the clip points should be within the bounding box
for ( i = 0 ; i < numClipPoints ; i++ ) {
int j;
for ( j = 0 ; j < 3 ; j++ ) {
if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
}
if (j < 3) break;
}
if (i < numClipPoints) return;
*/
mf = fragmentBuffer + (*returnedFragments);
mf->firstPoint = (*returnedPoints);
mf->numPoints = numClipPoints;
memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
(*returnedPoints) += numClipPoints;
(*returnedFragments)++;
}
int RE_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer )
{
int numsurfaces, numPlanes;
int i, j, k, m, n;
surfaceType_t *surfaces[64];
vec3_t mins, maxs;
int returnedFragments;
int returnedPoints;
vec3_t normals[MAX_VERTS_ON_POLY+2];
float dists[MAX_VERTS_ON_POLY+2];
vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
int numClipPoints;
float *v;
srfSurfaceFace_t *surf;
srfGridMesh_t *cv;
drawVert_t *dv;
vec3_t normal;
vec3_t projectionDir;
vec3_t v1, v2;
int *indexes;
//increment view count for double check prevention
tr.viewCount++;
//
VectorNormalize2( projection, projectionDir );
// find all the brushes that are to be considered
ClearBounds( mins, maxs );
for ( i = 0 ; i < numPoints ; i++ ) {
vec3_t temp;
AddPointToBounds( points[i], mins, maxs );
VectorAdd( points[i], projection, temp );
AddPointToBounds( temp, mins, maxs );
// make sure we get all the leafs (also the one(s) in front of the hit surface)
VectorMA( points[i], -20, projectionDir, temp );
AddPointToBounds( temp, mins, maxs );
}
if (numPoints > MAX_VERTS_ON_POLY) numPoints = MAX_VERTS_ON_POLY;
// create the bounding planes for the to be projected polygon
for ( i = 0 ; i < numPoints ; i++ ) {
VectorSubtract(points[(i+1)%numPoints], points[i], v1);
VectorAdd(points[i], projection, v2);
VectorSubtract(points[i], v2, v2);
CrossProduct(v1, v2, normals[i]);
VectorNorm(normals[i]);
dists[i] = DotProduct(normals[i], points[i]);
}
// add near and far clipping planes for projection
VectorCopy(projectionDir, normals[numPoints]);
dists[numPoints] = DotProduct(normals[numPoints], points[0]) - 32;
VectorCopy(projectionDir, normals[numPoints+1]);
VectorInverse(normals[numPoints+1]);
dists[numPoints+1] = DotProduct(normals[numPoints+1], points[0]) - 20;
numPlanes = numPoints + 2;
numsurfaces = 0;
R_BoxSurfaces_r(tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir);
//assert(numsurfaces <= 64);
//assert(numsurfaces != 64);
returnedPoints = 0;
returnedFragments = 0;
for ( i = 0 ; i < numsurfaces ; i++ ) {
if (*surfaces[i] == SF_GRID) {
cv = (srfGridMesh_t *) surfaces[i];
for ( m = 0 ; m < cv->height - 1 ; m++ ) {
for ( n = 0 ; n < cv->width - 1 ; n++ ) {
// We triangulate the grid and chop all triangles within
// the bounding planes of the to be projected polygon.
// LOD is not taken into account, not such a big deal though.
//
// It's probably much nicer to chop the grid itself and deal
// with this grid as a normal SF_GRID surface so LOD will
// be applied. However the LOD of that chopped grid must
// be synced with the LOD of the original curve.
// One way to do this; the chopped grid shares vertices with
// the original curve. When LOD is applied to the original
// curve the unused vertices are flagged. Now the chopped curve
// should skip the flagged vertices. This still leaves the
// problems with the vertices at the chopped grid edges.
//
// To avoid issues when LOD applied to "hollow curves" (like
// the ones around many jump pads) we now just add a 2 unit
// offset to the triangle vertices.
// The offset is added in the vertex normal vector direction
// so all triangles will still fit together.
// The 2 unit offset should avoid pretty much all LOD problems.
numClipPoints = 3;
dv = cv->verts + m * cv->width + n;
VectorCopy(dv[0].xyz, clipPoints[0][0]);
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]);
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
VectorCopy(dv[1].xyz, clipPoints[0][2]);
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]);
// check the normal of this triangle
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
CrossProduct(v1, v2, normal);
VectorNorm(normal);
if (DotProduct(normal, projectionDir) < -0.1) {
// add the fragments of this triangle
R_AddMarkFragments(numClipPoints, clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer,
&returnedPoints, &returnedFragments, mins, maxs);
if ( returnedFragments == maxFragments ) {
return returnedFragments; // not enough space for more fragments
}
}
VectorCopy(dv[1].xyz, clipPoints[0][0]);
VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]);
VectorCopy(dv[cv->width].xyz, clipPoints[0][1]);
VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]);
VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]);
VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]);
// check the normal of this triangle
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
CrossProduct(v1, v2, normal);
VectorNorm(normal);
if (DotProduct(normal, projectionDir) < -0.05) {
// add the fragments of this triangle
R_AddMarkFragments(numClipPoints, clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer,
&returnedPoints, &returnedFragments, mins, maxs);
if ( returnedFragments == maxFragments ) {
return returnedFragments; // not enough space for more fragments
}
}
}
}
}
else if (*surfaces[i] == SF_FACE) {
surf = ( srfSurfaceFace_t * ) surfaces[i];
// check the normal of this face
if (DotProduct(surf->plane.normal, projectionDir) > -0.5) {
continue;
}
/*
VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1);
VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2);
CrossProduct(v1, v2, normal);
VectorNormalize(normal);
if (DotProduct(normal, projectionDir) > -0.5) continue;
*/
indexes = (int *)( (byte *)surf + surf->ofsIndices );
for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
for ( j = 0 ; j < 3 ; j++ ) {
v = surf->points[0] + VERTEXSIZE * indexes[k+j];;
VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
}
// add the fragments of this face
R_AddMarkFragments( 3 , clipPoints,
numPlanes, normals, dists,
maxPoints, pointBuffer,
maxFragments, fragmentBuffer,
&returnedPoints, &returnedFragments, mins, maxs);
if ( returnedFragments == maxFragments ) {
return returnedFragments; // not enough space for more fragments
}
}
continue;
}
else {
// ignore all other world surfaces
// might be cool to also project polygons on a triangle soup
// however this will probably create huge amounts of extra polys
// even more than the projection onto curves
continue;
}
}
return returnedFragments;
}

347
code/renderervk/tr_mesh.c Normal file
View file

@ -0,0 +1,347 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_mesh.c: triangle model functions
#include "tr_local.h"
#include "tr_globals.h"
#include "tr_cvar.h"
#include "vk_shade_geometry.h"
#include "ref_import.h"
#include "tr_light.h"
static int R_CullModel( md3Header_t *header, trRefEntity_t *ent )
{
vec3_t bounds[2];
int i;
// compute frame pointers
md3Frame_t* newFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
md3Frame_t* oldFrame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.oldframe;
// cull bounding sphere ONLY if this is not an upscaled entity
if ( !ent->e.nonNormalizedAxes )
{
if ( ent->e.frame == ent->e.oldframe )
{
switch ( R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius ) )
{
case CULL_OUT:
tr.pc.c_sphere_cull_md3_out++;
return CULL_OUT;
case CULL_IN:
tr.pc.c_sphere_cull_md3_in++;
return CULL_IN;
case CULL_CLIP:
tr.pc.c_sphere_cull_md3_clip++;
break;
}
}
else
{
int sphereCull, sphereCullB;
sphereCull = R_CullLocalPointAndRadius( newFrame->localOrigin, newFrame->radius );
if ( newFrame == oldFrame ) {
sphereCullB = sphereCull;
} else {
sphereCullB = R_CullLocalPointAndRadius( oldFrame->localOrigin, oldFrame->radius );
}
if ( sphereCull == sphereCullB )
{
if ( sphereCull == CULL_OUT )
{
tr.pc.c_sphere_cull_md3_out++;
return CULL_OUT;
}
else if ( sphereCull == CULL_IN )
{
tr.pc.c_sphere_cull_md3_in++;
return CULL_IN;
}
else
{
tr.pc.c_sphere_cull_md3_clip++;
}
}
}
}
// calculate a bounding box in the current coordinate system
for (i = 0 ; i < 3 ; i++) {
bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
}
switch ( R_CullLocalBox( bounds ) )
{
case CULL_IN:
tr.pc.c_box_cull_md3_in++;
return CULL_IN;
case CULL_CLIP:
tr.pc.c_box_cull_md3_clip++;
return CULL_CLIP;
case CULL_OUT:
default:
tr.pc.c_box_cull_md3_out++;
return CULL_OUT;
}
}
int R_ComputeLOD( trRefEntity_t *ent )
{
int lod = 0;
float radius;
// radius are guarentee large than 0;
// multiple LODs exist, so compute projected bounding sphere
// and use that as a criteria for selecting LOD
if(tr.currentModel->type == MOD_MDR)
{
mdrHeader_t * mdr = (mdrHeader_t *) tr.currentModel->modelData;
int frameSize = (size_t) (&((mdrFrame_t *)0)->bones[mdr->numBones]);
mdrFrame_t * mdrframe = (mdrFrame_t *) ((byte *) mdr + mdr->ofsFrames + frameSize * ent->e.frame);
radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]);
}
else
{
md3Frame_t * frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames );
frame += ent->e.frame;
radius = RadiusFromBounds( frame->bounds[0], frame->bounds[1] );
}
float tmpVec[3];
VectorSubtract(ent->e.origin, tr.viewParms.or.origin, tmpVec);
float dist = DotProduct( tr.viewParms.or.axis[0], tmpVec);
if ( dist > 0 )
{
// vec3_t p;
// p[0] = 0;
// p[1] = r ;
// p[2] = -dist;
// p[3] = 1;
// pMatProj = tr.viewParms.projectionMatrix
// float projected[4];
// projected[0] = p[0] * pMatProj[0] + p[1] * pMatProj[4] + p[2] * pMatProj[8] + pMatProj[12];
// projected[1] = p[0] * pMatProj[1] - p[1] * pMatProj[5] + p[2] * pMatProj[9] + pMatProj[13];
// projected[2] = p[0] * pMatProj[2] + p[1] * pMatProj[6] + p[2] * pMatProj[10] + pMatProj[14];
// projected[3] = p[0] * pMatProj[3] + p[1] * pMatProj[7] + p[2] * pMatProj[11] + pMatProj[15];
// perspective devide
// pr = projected[1] / projected[3];
float p1 = - radius * tr.viewParms.projectionMatrix[5] - dist * tr.viewParms.projectionMatrix[9] + tr.viewParms.projectionMatrix[13];
float p3 = radius * tr.viewParms.projectionMatrix[7] - dist * tr.viewParms.projectionMatrix[11] + tr.viewParms.projectionMatrix[15];
float projectedRadius = p1 / p3;
//ri.Printf( PRINT_ALL, "%f: \n", projectedRadius);
lod = (1.0f - projectedRadius * 6 ) * tr.currentModel->numLods;
if ( lod < 0 )
{
lod = 0;
}
else if ( lod >= tr.currentModel->numLods )
{
lod = tr.currentModel->numLods - 1;
}
}
return lod;
}
/*
=================
R_ComputeFogNum
=================
*/
int R_ComputeFogNum( md3Header_t *header, trRefEntity_t *ent ) {
int i, j;
fog_t *fog;
md3Frame_t *md3Frame;
vec3_t localOrigin;
if ( tr.refdef.rd.rdflags & RDF_NOWORLDMODEL ) {
return 0;
}
// FIXME: non-normalized axis issues
md3Frame = ( md3Frame_t * ) ( ( byte * ) header + header->ofsFrames ) + ent->e.frame;
VectorAdd( ent->e.origin, md3Frame->localOrigin, localOrigin );
for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
fog = &tr.world->fogs[i];
for ( j = 0 ; j < 3 ; j++ ) {
if ( localOrigin[j] - md3Frame->radius >= fog->bounds[1][j] ) {
break;
}
if ( localOrigin[j] + md3Frame->radius <= fog->bounds[0][j] ) {
break;
}
}
if ( j == 3 ) {
return i;
}
}
return 0;
}
void R_AddMD3Surfaces( trRefEntity_t *ent )
{
int i;
md3Header_t *header = NULL;
md3Surface_t *surface = NULL;
md3Shader_t *md3Shader = NULL;
shader_t *shader = NULL;
int cull;
int lod = 0;
int fogNum;
// don't add third_person objects if not in a portal
qboolean personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal;
if ( ent->e.renderfx & RF_WRAP_FRAMES ) {
ent->e.frame %= tr.currentModel->md3[0]->numFrames;
ent->e.oldframe %= tr.currentModel->md3[0]->numFrames;
}
//
// Validate the frames so there is no chance of a crash.
// This will write directly into the entity structure, so
// when the surfaces are rendered, they don't need to be
// range checked again.
if ( (ent->e.frame >= tr.currentModel->md3[0]->numFrames)
|| (ent->e.frame < 0)
|| (ent->e.oldframe >= tr.currentModel->md3[0]->numFrames)
|| (ent->e.oldframe < 0) )
{
ri.Printf( PRINT_ALL, "R_AddMD3Surfaces: no such frame %d to %d for '%s'\n",
ent->e.oldframe, ent->e.frame,
tr.currentModel->name );
ent->e.frame = 0;
ent->e.oldframe = 0;
}
//
// compute LOD
// model has only 1 LOD level, skip computations and bias
if ( tr.currentModel->numLods > 1 )
lod = R_ComputeLOD( ent );
header = tr.currentModel->md3[lod];
//
// cull the entire model if merged bounding box of both frames
// is outside the view frustum.
//
cull = R_CullModel ( header, ent );
if ( cull == CULL_OUT ) {
return;
}
//
// set up lighting now that we know we aren't culled
//
if ( !personalModel) {
R_SetupEntityLighting( &tr.refdef, ent );
}
//
// draw all surfaces
//
surface = (md3Surface_t *)( (byte *)header + header->ofsSurfaces );
for ( i = 0 ; i < header->numSurfaces ; i++ )
{
if ( ent->e.customShader )
{
shader = R_GetShaderByHandle( ent->e.customShader );
}
else if ( ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins )
{
skin_t *skin = R_GetSkinByHandle( ent->e.customSkin );
// match the surface name to something in the skin file
shader = tr.defaultShader;
int j;
for ( j = 0 ; j < skin->numSurfaces ; j++ )
{
// the names have both been lowercased
if ( !strcmp( skin->pSurfaces[j].name, surface->name ) ) {
shader = skin->pSurfaces[j].shader;
break;
}
}
if (shader == tr.defaultShader) {
ri.Printf( PRINT_DEVELOPER, "no shader for surface %s in skin %s\n", surface->name, skin->name);
}
else if (shader->defaultShader) {
ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name);
}
} else if ( surface->numShaders <= 0 ) {
shader = tr.defaultShader;
} else {
md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders );
md3Shader += ent->e.skinNum % surface->numShaders;
shader = tr.shaders[ md3Shader->shaderIndex ];
}
// we will add shadows even if the main object isn't visible in the view
// don't add third_person objects if not viewing through a portal
if ( !personalModel )
{
// see if we are in a fog volume
fogNum = R_ComputeFogNum( header, ent );
R_AddDrawSurf( (void *)surface, shader, fogNum, qfalse );
}
surface = (md3Surface_t *)( (byte *)surface + surface->ofsEnd );
}
}

View file

@ -0,0 +1,81 @@
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_models.c -- model loading and caching
#include "tr_local.h"
#include "tr_globals.h"
#include "tr_model.h"
#include "ref_import.h"
model_t* R_GetModelByHandle( qhandle_t index )
{
if ( (index < 0) || (index >= tr.numModels) )
{
ri.Printf(PRINT_WARNING, "index = %d, out of range gets the defualt model.\n", index);
return tr.models[0];
}
return tr.models[index];
}
///////////////////////////////////////////////////////////////////////////////
void R_ModelInit( void )
{
ri.Printf( PRINT_ALL, "R_ModelInit: \n");
// leave a space for NULL model
model_t* mod = ri.Hunk_Alloc( sizeof( model_t ), h_low );
mod->index = tr.numModels = 0;
mod->type = MOD_BAD;
tr.models[tr.numModels] = mod;
tr.numModels++;
}
void R_Modellist_f( void )
{
int i;
int total = 0;
for ( i = 1 ; i < tr.numModels; i++ )
{
model_t* mod = tr.models[i];
int lods = 1;
int j;
for ( j = 1 ; j < MD3_MAX_LODS ; j++ )
{
if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] )
{
lods++;
}
}
ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name );
total += mod->dataSize;
}
ri.Printf( PRINT_ALL, "%8i : Total models\n", total );
}

102
code/renderervk/tr_model.h Normal file
View file

@ -0,0 +1,102 @@
#ifndef TR_MODEL_H_
#define TR_MODEL_H_
#include "../renderercommon/iqm.h"
typedef enum {
MOD_BAD,
MOD_BRUSH,
MOD_MESH,
MOD_MDR,
MOD_IQM
} modtype_t;
typedef struct model_s {
char name[MAX_QPATH];
modtype_t type;
int index; // model = tr.models[model->index]
int dataSize; // just for listing purposes
bmodel_t *bmodel; // only if type == MOD_BRUSH
md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH
void *modelData; // only if type == (MOD_MDR | MOD_IQM)
int numLods;
} model_t;
#define MAX_MOD_KNOWN 1024
void R_ModelInit( void );
model_t* R_GetModelByHandle( qhandle_t hModel );
void R_Modellist_f( void );
//====================================================
qhandle_t R_RegisterMD3(const char *name, model_t *mod);
qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name );
qhandle_t R_RegisterMDR(const char *name, model_t *mod);
qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name );
qhandle_t R_RegisterIQM(const char *name, model_t *mod);
//====================================================
// IQM
// inter-quake-model
typedef struct {
int num_vertexes;
int num_triangles;
int num_frames;
int num_surfaces;
int num_joints;
int num_poses;
struct srfIQModel_s *surfaces;
float *positions;
float *texcoords;
float *normals;
float *tangents;
byte *blendIndexes;
union {
float *f;
byte *b;
} blendWeights;
byte *colors;
int *triangles;
// depending upon the exporter, blend indices and weights might be int/float
// as opposed to the recommended byte/byte, for example Noesis exports
// int/float whereas the official IQM tool exports byte/byte
byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT
int *jointParents;
float *jointMats;
float *poseMats;
float *bounds;
char *names;
} iqmData_t;
// inter-quake-model surface
typedef struct srfIQModel_s {
surfaceType_t surfaceType;
char name[MAX_QPATH];
shader_t *shader;
iqmData_t *data;
int first_vertex, num_vertexes;
int first_triangle, num_triangles;
} srfIQModel_t;
void R_AddIQMSurfaces( trRefEntity_t *ent );
void RB_IQMSurfaceAnim( surfaceType_t *surface );
void ComputePoseMats( iqmData_t *data, int frame, int oldframe, float backlerp, float *mat );
#endif

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