+/*
+==============
+VM_vectorvectors
+
+Writes new values for v_forward, v_up, and v_right based on the given forward vector
+vectorvectors(vector, vector)
+==============
+*/
+void VM_vectorvectors (void)
+{
+ VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward);
+ VectorVectors(prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
+}
+
+/*
+========================
+VM_drawline
+
+void drawline(float width, vector pos1, vector pos2, vector rgb, float alpha, float flags)
+========================
+*/
+void VM_drawline (void)
+{
+ float *c1, *c2, *rgb;
+ float alpha, width;
+ unsigned char flags;
+
+ VM_SAFEPARMCOUNT(6, VM_drawline);
+ width = PRVM_G_FLOAT(OFS_PARM0);
+ c1 = PRVM_G_VECTOR(OFS_PARM1);
+ c2 = PRVM_G_VECTOR(OFS_PARM2);
+ rgb = PRVM_G_VECTOR(OFS_PARM3);
+ alpha = PRVM_G_FLOAT(OFS_PARM4);
+ flags = PRVM_G_FLOAT(OFS_PARM5);
+ DrawQ_Line(width, c1[0], c1[1], c2[0], c2[1], rgb[0], rgb[1], rgb[2], alpha, flags);
+}
+
+//====================
+//QC POLYGON functions
+//====================
+
+typedef struct
+{
+ rtexture_t *tex;
+ float data[36]; //[515]: enough for polygons
+ unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
+}vm_polygon_t;
+
+//static float vm_polygon_linewidth = 1;
+static mempool_t *vm_polygons_pool = NULL;
+static unsigned char vm_current_vertices = 0;
+static qboolean vm_polygons_initialized = false;
+static vm_polygon_t *vm_polygons = NULL;
+static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
+static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
+#define VM_DEFPOLYNUM 64 //[515]: enough for default ?
+
+#define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
+#define VM_POLYGON_FLLINES 32
+#define VM_POLYGON_FL2D 64
+#define VM_POLYGON_FL4V 128 //4 vertices
+
+void VM_InitPolygons (void)
+{
+ vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
+ vm_polygons = Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
+ memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
+ vm_polygons_num = VM_DEFPOLYNUM;
+ vm_polygonbegin = vm_drawpolygons_num = 0;
+ vm_polygons_initialized = true;
+}
+
+void VM_DrawPolygonCallback (const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+{
+ const vm_polygon_t *p = &vm_polygons[surfacenumber];
+ int flags = p->flags & 0x0f;
+
+ if(flags == DRAWFLAG_ADDITIVE)
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ else if(flags == DRAWFLAG_MODULATE)
+ GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
+ else if(flags == DRAWFLAG_2XMODULATE)
+ GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
+ else
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ R_Mesh_TexBind(0, R_GetTexture(p->tex));
+
+ //[515]: is speed is max ?
+ if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
+ {
+ qglLineWidth(p->data[13]);
+ qglBegin(GL_LINE_LOOP);
+ qglTexCoord1f (p->data[12]);
+ qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
+ qglVertex3f (p->data[0] , p->data[1], p->data[2]);
+
+ qglTexCoord1f (p->data[14]);
+ qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
+ qglVertex3f (p->data[3] , p->data[4], p->data[5]);
+
+ if(p->flags & VM_POLYGON_FL3V)
+ {
+ qglTexCoord1f (p->data[16]);
+ qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
+ qglVertex3f (p->data[6] , p->data[7], p->data[8]);
+
+ if(p->flags & VM_POLYGON_FL4V)
+ {
+ qglTexCoord1f (p->data[18]);
+ qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
+ qglVertex3f (p->data[9] , p->data[10], p->data[11]);
+ }
+ }
+ qglEnd();
+ }
+ else
+ {
+ qglBegin(GL_POLYGON);
+ qglTexCoord2f (p->data[12], p->data[13]);
+ qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
+ qglVertex3f (p->data[0] , p->data[1], p->data[2]);
+
+ qglTexCoord2f (p->data[14], p->data[15]);
+ qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
+ qglVertex3f (p->data[3] , p->data[4], p->data[5]);
+
+ qglTexCoord2f (p->data[16], p->data[17]);
+ qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
+ qglVertex3f (p->data[6] , p->data[7], p->data[8]);
+
+ if(p->flags & VM_POLYGON_FL4V)
+ {
+ qglTexCoord2f (p->data[18], p->data[19]);
+ qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
+ qglVertex3f (p->data[9] , p->data[10], p->data[11]);
+ }
+ qglEnd();
+ }
+}
+
+void VM_AddPolygonTo2DScene (vm_polygon_t *p)
+{
+ drawqueuemesh_t mesh;
+ static int picelements[6] = {0, 1, 2, 0, 2, 3};
+
+ mesh.texture = p->tex;
+ mesh.data_element3i = picelements;
+ mesh.data_vertex3f = p->data;
+ mesh.data_texcoord2f = p->data + 12;
+ mesh.data_color4f = p->data + 20;
+ if(p->flags & VM_POLYGON_FL4V)
+ {
+ mesh.num_vertices = 4;
+ mesh.num_triangles = 2;
+ }
+ else
+ {
+ mesh.num_vertices = 3;
+ mesh.num_triangles = 1;
+ }
+ if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
+ DrawQ_LineLoop (&mesh, (p->flags&0x0f));
+ else
+ DrawQ_Mesh (&mesh, (p->flags&0x0f));
+}
+
+//void(string texturename, float flag, float 2d, float lines) R_BeginPolygon
+void VM_R_PolygonBegin (void)
+{
+ vm_polygon_t *p;
+ const char *picname;
+ if(prog->argc < 2)
+ VM_SAFEPARMCOUNT(2, VM_R_PolygonBegin);
+
+ if(!vm_polygons_initialized)
+ VM_InitPolygons();
+ if(vm_polygonbegin)
+ {
+ Con_Printf("VM_R_PolygonBegin: called twice without VM_R_PolygonEnd after first\n");
+ return;
+ }
+ if(vm_drawpolygons_num >= vm_polygons_num)
+ {
+ p = Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
+ memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
+ memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
+ Mem_Free(vm_polygons);
+ vm_polygons = p;
+ vm_polygons_num *= 2;
+ }
+ p = &vm_polygons[vm_drawpolygons_num];
+ picname = PRVM_G_STRING(OFS_PARM0);
+ if(picname[0])
+ p->tex = Draw_CachePic(picname, false)->tex;
+ else
+ p->tex = r_texture_notexture;
+ p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
+ vm_current_vertices = 0;
+ vm_polygonbegin = true;
+ if(prog->argc >= 3)
+ {
+ if(PRVM_G_FLOAT(OFS_PARM2))
+ p->flags |= VM_POLYGON_FL2D;
+ if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
+ {
+ p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
+ p->flags |= VM_POLYGON_FLLINES;
+ }
+ }
+}
+
+//void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
+void VM_R_PolygonVertex (void)
+{
+ float *coords, *tx, *rgb, alpha;
+ vm_polygon_t *p;
+ VM_SAFEPARMCOUNT(4, VM_R_PolygonVertex);
+
+ if(!vm_polygonbegin)
+ {
+ Con_Printf("VM_R_PolygonVertex: VM_R_PolygonBegin wasn't called\n");
+ return;
+ }
+ coords = PRVM_G_VECTOR(OFS_PARM0);
+ tx = PRVM_G_VECTOR(OFS_PARM1);
+ rgb = PRVM_G_VECTOR(OFS_PARM2);
+ alpha = PRVM_G_FLOAT(OFS_PARM3);
+
+ p = &vm_polygons[vm_drawpolygons_num];
+ if(vm_current_vertices > 4)
+ {
+ Con_Printf("VM_R_PolygonVertex: may have 4 vertices max\n");
+ return;
+ }
+
+ p->data[vm_current_vertices*3] = coords[0];
+ p->data[1+vm_current_vertices*3] = coords[1];
+ if(!(p->flags & VM_POLYGON_FL2D))
+ p->data[2+vm_current_vertices*3] = coords[2];
+
+ p->data[12+vm_current_vertices*2] = tx[0];
+ if(!(p->flags & VM_POLYGON_FLLINES))
+ p->data[13+vm_current_vertices*2] = tx[1];
+
+ p->data[20+vm_current_vertices*4] = rgb[0];
+ p->data[21+vm_current_vertices*4] = rgb[1];
+ p->data[22+vm_current_vertices*4] = rgb[2];
+ p->data[23+vm_current_vertices*4] = alpha;
+
+ vm_current_vertices++;
+ if(vm_current_vertices == 4)
+ p->flags |= VM_POLYGON_FL4V;
+ else
+ if(vm_current_vertices == 3)
+ p->flags |= VM_POLYGON_FL3V;
+}
+
+//void() R_EndPolygon
+void VM_R_PolygonEnd (void)
+{
+ if(!vm_polygonbegin)
+ {
+ Con_Printf("VM_R_PolygonEnd: VM_R_PolygonBegin wasn't called\n");
+ return;
+ }
+ if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
+ {
+ if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
+ VM_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
+ else
+ vm_drawpolygons_num++;
+ }
+ else
+ Con_Printf("VM_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
+ vm_polygonbegin = false;
+}
+
+void VM_AddPolygonsToMeshQueue (void)
+{
+ unsigned int i;
+ if(!vm_drawpolygons_num)
+ return;
+ for(i = 0;i < vm_drawpolygons_num;i++)
+ R_MeshQueue_Add(VM_DrawPolygonCallback, NULL, i, NULL);
+ vm_drawpolygons_num = 0;
+}
+
+
+
+
+// float(float number, float quantity) bitshift (EXT_BITSHIFT)
+void VM_bitshift (void)
+{
+ int n1, n2;
+ VM_SAFEPARMCOUNT(2, VM_bitshift);
+
+ n1 = (int)fabs((int)PRVM_G_FLOAT(OFS_PARM0));
+ n2 = (int)PRVM_G_FLOAT(OFS_PARM1);
+ if(!n1)
+ PRVM_G_FLOAT(OFS_RETURN) = n1;
+ else
+ if(n2 < 0)
+ PRVM_G_FLOAT(OFS_RETURN) = (n1 >> -n2);
+ else
+ PRVM_G_FLOAT(OFS_RETURN) = (n1 << n2);
+}
+