68478eab4b
but couldn't release immediately since they depended on virtual GPU features which were not yet publicly released in any products. This checkin moves those features from our internal repository to the open source repository. Future development on these tests and examples will take place directly in the open source repository. The primary feature added by this patch is 'Screen Object', a new dynamic display management extension supported by Workstation 7.0 and Fusion 3.0. See the README for a quick explanation.
632 lines
17 KiB
C
632 lines
17 KiB
C
/*
|
|
* This is a test which demonstrates many features of the Screen
|
|
* Object rendering model:
|
|
*
|
|
* - GMR-to-screen blits from multiple GMRFBs onto multiple screens
|
|
* - SVGA3D-to-screen blits, with scaling, onto multiple screens
|
|
* - screen-to-GMR blits
|
|
* - Video Overlay with GMRs and Screen Objects
|
|
*
|
|
* For a complete test of Screen Object, several other tests are also
|
|
* necessary:
|
|
*
|
|
* - Per-screen cursors (screen-multimon test)
|
|
* - Screen creation, destruction, and redefinition (screen-multimon)
|
|
* - Checkpointing
|
|
*
|
|
* This example requires SVGA Screen Object and SVGA3D support.
|
|
*/
|
|
|
|
#include "svga.h"
|
|
#include "svga3d.h"
|
|
#include "svga3dutil.h"
|
|
#include "matrix.h"
|
|
#include "math.h"
|
|
#include "gmr.h"
|
|
#include "screen.h"
|
|
#include "intr.h"
|
|
#include "screendraw.h"
|
|
#include "datafile.h"
|
|
|
|
/*
|
|
* 3D Rendering Definitions
|
|
*/
|
|
|
|
typedef struct {
|
|
float position[3];
|
|
uint32 color;
|
|
} MyVertex;
|
|
|
|
uint32 vertexSid, indexSid;
|
|
|
|
const int surfWidth = 1024;
|
|
const int surfHeight = 512;
|
|
|
|
SVGA3dSurfaceImageId colorImage;
|
|
SVGA3dSurfaceImageId depthImage;
|
|
|
|
static const MyVertex vertexData[] = {
|
|
{ {-1, -1, -1}, 0xFFFFFFFF },
|
|
{ {-1, -1, 1}, 0xFFFFFF00 },
|
|
{ {-1, 1, -1}, 0xFFFF00FF },
|
|
{ {-1, 1, 1}, 0xFFFF0000 },
|
|
{ { 1, -1, -1}, 0xFF00FFFF },
|
|
{ { 1, -1, 1}, 0xFF00FF00 },
|
|
{ { 1, 1, -1}, 0xFF0000FF },
|
|
{ { 1, 1, 1}, 0xFF000000 },
|
|
};
|
|
|
|
#define QUAD(a,b,c,d) a, b, d, d, c, a
|
|
static const uint16 indexData[] = {
|
|
QUAD(0,1,2,3), // -X
|
|
QUAD(4,5,6,7), // +X
|
|
QUAD(0,1,4,5), // -Y
|
|
QUAD(2,3,6,7), // +Y
|
|
QUAD(0,2,4,6), // -Z
|
|
QUAD(1,3,5,7), // +Z
|
|
};
|
|
#undef QUAD
|
|
|
|
const uint32 numTriangles = arraysize(indexData) / 3;
|
|
|
|
|
|
/*
|
|
* initScreens --
|
|
*
|
|
* Set up our Screen Objects, and label them.
|
|
*/
|
|
|
|
void
|
|
initScreens(void)
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* Define two screens:
|
|
*
|
|
* +-------+
|
|
* |0 |
|
|
* | |
|
|
* +--+----+-+
|
|
* |1 |
|
|
* +------+
|
|
*
|
|
* The screen 0 is 799x405, the screen 1 is 600x200.
|
|
* Neither screen is rooted at 0,0.
|
|
*/
|
|
|
|
SVGAScreenObject screens[] = {
|
|
{
|
|
.structSize = sizeof(SVGAScreenObject),
|
|
.id = 0,
|
|
.flags = SVGA_SCREEN_HAS_ROOT | SVGA_SCREEN_IS_PRIMARY,
|
|
.size = { 799, 405 },
|
|
.root = { -1234, 5678 },
|
|
},
|
|
{
|
|
.structSize = sizeof(SVGAScreenObject),
|
|
.id = 1,
|
|
.flags = SVGA_SCREEN_HAS_ROOT,
|
|
.size = { 600, 200 },
|
|
.root = { -1234 + 302, 5678 + 405 },
|
|
},
|
|
};
|
|
|
|
for (i = 0; i < arraysize(screens); i++) {
|
|
const SVGAScreenObject *screen = &screens[i];
|
|
|
|
Screen_Define(screen);
|
|
|
|
ScreenDraw_SetScreen(screen->id, screen->size.width, screen->size.height);
|
|
Console_Clear();
|
|
Console_MoveTo(5, screen->size.height - 20);
|
|
Console_Format("Screen #%d\n", screen->id);
|
|
ScreenDraw_Border(0, 0, screen->size.width, screen->size.height, 0xFF0000, 1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* initOverlays --
|
|
*
|
|
* Set up a video overlay using a non-default screen ID and a
|
|
* system memory GMR. These are both new features included in
|
|
* the Screen Object extension.
|
|
*/
|
|
|
|
void
|
|
initOverlays(void)
|
|
{
|
|
/*
|
|
* A video test card, in UYVY format.
|
|
*
|
|
* It's a 720x576 pixel 4:3 aspect test card designed by Barney
|
|
* Wol. (http://www.barney-wol.net/testpatterns)
|
|
*
|
|
* Decompress it into a new system memory GMR.
|
|
*/
|
|
DECLARE_DATAFILE(testCardFile, wols4x3_yuv_z);
|
|
|
|
const uint32 gmrId = 1;
|
|
const int videoWidth = 720;
|
|
const int videoHeight = 576;
|
|
const int videoBytes = videoWidth * videoHeight * 2;
|
|
const int videoPages = (videoBytes + PAGE_MASK) / PAGE_SIZE;
|
|
|
|
PPN videoFirstPage = GMR_DefineContiguous(gmrId, videoPages);
|
|
DataFile_Decompress(testCardFile, PPN_POINTER(videoFirstPage), videoBytes);
|
|
|
|
/*
|
|
* Display the video using Screen 1's coordinate system, but
|
|
* actually have it overlap the right edge of the line segment that
|
|
* screens 0 and 1 share.
|
|
*/
|
|
|
|
SVGAOverlayUnit overlay = {
|
|
.enabled = TRUE,
|
|
.format = VMWARE_FOURCC_UYVY,
|
|
.flags = SVGA_VIDEO_FLAG_COLORKEY,
|
|
.colorKey = 0x000000,
|
|
.width = videoWidth,
|
|
.height = videoHeight,
|
|
.srcWidth = videoWidth,
|
|
.srcHeight = videoHeight,
|
|
.pitches[0] = videoWidth * 2,
|
|
|
|
.dataGMRId = gmrId,
|
|
.dataOffset = 0,
|
|
|
|
.dstX = 220,
|
|
.dstY = -100,
|
|
.dstWidth = 320,
|
|
.dstHeight = 240,
|
|
.dstScreenId = 1,
|
|
};
|
|
|
|
SVGA_VideoSetAllRegs(0, &overlay, SVGA_VIDEO_DST_SCREEN_ID);
|
|
|
|
/*
|
|
* XXX: Flush twice, to work around a bug in legacy backends.
|
|
* New SWB backends don't have this problem, but it's harmless.
|
|
*/
|
|
SVGA_VideoFlush(0);
|
|
SVGA_VideoFlush(0);
|
|
|
|
/*
|
|
* Draw a border around the video
|
|
*/
|
|
ScreenDraw_SetScreen(1, 0, 0);
|
|
ScreenDraw_Border(overlay.dstX - 1, overlay.dstY - 1,
|
|
overlay.dstX + overlay.dstWidth + 1,
|
|
overlay.dstY + overlay.dstHeight + 1,
|
|
0xFFFF00, 1);
|
|
|
|
/*
|
|
* Some text to explain the video
|
|
*/
|
|
Console_MoveTo(overlay.dstX, overlay.dstY + overlay.dstHeight + 5);
|
|
Console_Format("Video overlay on Screen 1, sysmem GMR");
|
|
}
|
|
|
|
|
|
/*
|
|
* setup3D --
|
|
*
|
|
* Allocate 3D resources that are used by draw3D() and cubeLoop().
|
|
*/
|
|
|
|
void
|
|
setup3D(void)
|
|
{
|
|
/*
|
|
* Set up some 3D resources: A color buffer, depth buffer, vertex
|
|
* buffer, and index buffer. Load the VB and IB with data for a
|
|
* cube with unique vertex colors.
|
|
*/
|
|
|
|
colorImage.sid = SVGA3DUtil_DefineSurface2D(surfWidth, surfHeight, SVGA3D_X8R8G8B8);
|
|
depthImage.sid = SVGA3DUtil_DefineSurface2D(surfWidth, surfHeight, SVGA3D_Z_D16);
|
|
|
|
SVGA3D_DefineContext(CID);
|
|
|
|
vertexSid = SVGA3DUtil_DefineStaticBuffer(vertexData, sizeof vertexData);
|
|
indexSid = SVGA3DUtil_DefineStaticBuffer(indexData, sizeof indexData);
|
|
}
|
|
|
|
|
|
/*
|
|
* drawCube --
|
|
*
|
|
* Draw a cube with the specified viewport and background color.
|
|
* Every time we draw a cube, it rotates a little.
|
|
*/
|
|
|
|
void
|
|
drawCube(SVGA3dRect *viewport, uint32 bgColor)
|
|
{
|
|
static float angle = 0.5f;
|
|
SVGA3dRect *rect;
|
|
Matrix perspectiveMat;
|
|
SVGA3dTextureState *ts;
|
|
SVGA3dRenderState *rs;
|
|
|
|
SVGA3D_SetRenderTarget(CID, SVGA3D_RT_COLOR0, &colorImage);
|
|
SVGA3D_SetRenderTarget(CID, SVGA3D_RT_DEPTH, &depthImage);
|
|
|
|
SVGA3D_SetViewport(CID, viewport);
|
|
SVGA3D_SetZRange(CID, 0.0f, 1.0f);
|
|
|
|
SVGA3D_BeginSetRenderState(CID, &rs, 5);
|
|
{
|
|
rs[0].state = SVGA3D_RS_BLENDENABLE;
|
|
rs[0].uintValue = FALSE;
|
|
|
|
rs[1].state = SVGA3D_RS_ZENABLE;
|
|
rs[1].uintValue = TRUE;
|
|
|
|
rs[2].state = SVGA3D_RS_ZWRITEENABLE;
|
|
rs[2].uintValue = TRUE;
|
|
|
|
rs[3].state = SVGA3D_RS_ZFUNC;
|
|
rs[3].uintValue = SVGA3D_CMP_LESS;
|
|
|
|
rs[4].state = SVGA3D_RS_LIGHTINGENABLE;
|
|
rs[4].uintValue = FALSE;
|
|
}
|
|
SVGA_FIFOCommitAll();
|
|
|
|
SVGA3D_BeginSetTextureState(CID, &ts, 4);
|
|
{
|
|
ts[0].stage = 0;
|
|
ts[0].name = SVGA3D_TS_BIND_TEXTURE;
|
|
ts[0].value = SVGA3D_INVALID_ID;
|
|
|
|
ts[1].stage = 0;
|
|
ts[1].name = SVGA3D_TS_COLOROP;
|
|
ts[1].value = SVGA3D_TC_SELECTARG1;
|
|
|
|
ts[2].stage = 0;
|
|
ts[2].name = SVGA3D_TS_COLORARG1;
|
|
ts[2].value = SVGA3D_TA_DIFFUSE;
|
|
|
|
ts[3].stage = 0;
|
|
ts[3].name = SVGA3D_TS_ALPHAARG1;
|
|
ts[3].value = SVGA3D_TA_DIFFUSE;
|
|
}
|
|
SVGA_FIFOCommitAll();
|
|
|
|
/*
|
|
* Clear unused areas of the surface to white
|
|
*/
|
|
SVGA3D_BeginClear(CID, SVGA3D_CLEAR_COLOR | SVGA3D_CLEAR_DEPTH,
|
|
0xFFFFFFFF, 1.0f, 0, &rect, 1);
|
|
rect->x = 0;
|
|
rect->y = 0;
|
|
rect->w = surfWidth;
|
|
rect->w = surfHeight;
|
|
SVGA_FIFOCommitAll();
|
|
|
|
/*
|
|
* Draw the background color
|
|
*/
|
|
SVGA3D_BeginClear(CID, SVGA3D_CLEAR_COLOR | SVGA3D_CLEAR_DEPTH,
|
|
bgColor | 0x42000000, 1.0f, 0, &rect, 1);
|
|
*rect = *viewport;
|
|
SVGA_FIFOCommitAll();
|
|
|
|
SVGA3dVertexDecl *decls;
|
|
SVGA3dPrimitiveRange *ranges;
|
|
Matrix view;
|
|
|
|
Matrix_Copy(view, gIdentityMatrix);
|
|
Matrix_Scale(view, 0.5, 0.5, 0.5, 1.0);
|
|
Matrix_RotateX(view, 30.0 * M_PI / 180.0);
|
|
Matrix_RotateY(view, angle);
|
|
Matrix_Translate(view, 0, 0, 2.5);
|
|
|
|
angle += 0.01;
|
|
|
|
Matrix_Perspective(perspectiveMat, 45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
|
|
SVGA3D_SetTransform(CID, SVGA3D_TRANSFORM_WORLD, gIdentityMatrix);
|
|
SVGA3D_SetTransform(CID, SVGA3D_TRANSFORM_PROJECTION, perspectiveMat);
|
|
SVGA3D_SetTransform(CID, SVGA3D_TRANSFORM_VIEW, view);
|
|
|
|
SVGA3D_BeginDrawPrimitives(CID, &decls, 2, &ranges, 1);
|
|
{
|
|
decls[0].identity.type = SVGA3D_DECLTYPE_FLOAT3;
|
|
decls[0].identity.usage = SVGA3D_DECLUSAGE_POSITION;
|
|
decls[0].array.surfaceId = vertexSid;
|
|
decls[0].array.stride = sizeof(MyVertex);
|
|
decls[0].array.offset = offsetof(MyVertex, position);
|
|
|
|
decls[1].identity.type = SVGA3D_DECLTYPE_D3DCOLOR;
|
|
decls[1].identity.usage = SVGA3D_DECLUSAGE_COLOR;
|
|
decls[1].array.surfaceId = vertexSid;
|
|
decls[1].array.stride = sizeof(MyVertex);
|
|
decls[1].array.offset = offsetof(MyVertex, color);
|
|
|
|
ranges[0].primType = SVGA3D_PRIMITIVE_TRIANGLELIST;
|
|
ranges[0].primitiveCount = numTriangles;
|
|
ranges[0].indexArray.surfaceId = indexSid;
|
|
ranges[0].indexArray.stride = sizeof(uint16);
|
|
ranges[0].indexWidth = sizeof(uint16);
|
|
}
|
|
SVGA_FIFOCommitAll();
|
|
}
|
|
|
|
|
|
/*
|
|
* draw3D --
|
|
*
|
|
* Set up some 3D resources, and draw a simple cube scene to
|
|
* several places on the frontbuffer. Each cube is drawn using a
|
|
* distinct background color.
|
|
*/
|
|
|
|
void
|
|
draw3D(void)
|
|
{
|
|
/*
|
|
* Scenes to render
|
|
*/
|
|
const int dstWidth = 160;
|
|
const int dstHeight = 120;
|
|
|
|
struct {
|
|
uint32 screenId;
|
|
SVGA3dRect viewport;
|
|
int x, y;
|
|
uint32 bgColor;
|
|
const char *label;
|
|
} scenes[] = {
|
|
/*
|
|
* These scenes all use different but overlapping parts of the
|
|
* render target, so it's quite obvious if the wrong image is
|
|
* being displayed- either you'll see part of the frame
|
|
* overwritten by a different frame, or the image will be
|
|
* misaligned.
|
|
*/
|
|
{ 0, { 123, 65, 160, 120 }, 320, 20 + 145 * 0, 0x800000, "Red" }, // Non-scaled
|
|
{ 0, { 150, 82, 320, 240 }, 320, 20 + 145 * 1, 0x008000, "Green" }, // Scaled
|
|
{ 0, { 85, 32, 400, 300 }, 320, 20 + 145 * 2, 0x000080, "Blue" }, // Scaled
|
|
{ 0, { 160, 40, 160, 120 }, 320, 20 + 145 * 3, 0xae3aff, "Purple" }, // Non-scaled
|
|
};
|
|
|
|
int i;
|
|
for (i = 0; i < arraysize(scenes); i++) {
|
|
drawCube(&scenes[i].viewport, scenes[i].bgColor);
|
|
|
|
SVGASignedRect srcRect = { scenes[i].viewport.x,
|
|
scenes[i].viewport.y,
|
|
scenes[i].viewport.x + scenes[i].viewport.w,
|
|
scenes[i].viewport.y + scenes[i].viewport.h };
|
|
SVGASignedRect dstRect = { scenes[i].x,
|
|
scenes[i].y,
|
|
scenes[i].x + dstWidth,
|
|
scenes[i].y + dstHeight };
|
|
|
|
/*
|
|
* Draw some text underneath the Present. If you can see this
|
|
* text, something is wrong.
|
|
*/
|
|
ScreenDraw_SetScreen(scenes[i].screenId, 0, 0);
|
|
Console_MoveTo(dstRect.left + 10, (dstRect.top + dstRect.bottom) / 2);
|
|
Console_WriteString("XXX: 2D!");
|
|
|
|
/*
|
|
* Present our scene to the front buffer using the new surface-to-screen blit.
|
|
*/
|
|
SVGA3D_BlitSurfaceToScreen(&colorImage, &srcRect,
|
|
scenes[i].screenId, &dstRect);
|
|
|
|
/*
|
|
* Draw on the frontbuffer to label this scene, and draw
|
|
* a border around it.
|
|
*/
|
|
ScreenDraw_SetScreen(scenes[i].screenId, 0, 0);
|
|
Console_MoveTo(dstRect.left, dstRect.top);
|
|
Console_WriteString(scenes[i].label);
|
|
ScreenDraw_Border(dstRect.left - 1, dstRect.top - 1,
|
|
dstRect.right + 1, dstRect.bottom + 1,
|
|
0xFFFF00, 1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* cubeLoop --
|
|
*
|
|
* Draw a spinning cube in an infinite loop, using the same
|
|
* backbuffer and other resources that we used on the earlier
|
|
* cubes.
|
|
*/
|
|
|
|
void
|
|
cubeLoop(void)
|
|
{
|
|
/* Draw a label */
|
|
ScreenDraw_SetScreen(1, 0, 0);
|
|
Console_MoveTo(230, -265);
|
|
Console_WriteString("Spinning, Orange:");
|
|
|
|
while (1) {
|
|
SVGA3dRect viewport = { 0, 0, 160, 120 };
|
|
SVGASignedRect srcRect = { 0, 0, 160, 120 };
|
|
SVGASignedRect dstRect = { 230, -245, 230+160, -245+120 };
|
|
|
|
drawCube(&viewport, 0xd9a54a);
|
|
SVGA3D_BlitSurfaceToScreen(&colorImage, &srcRect, 1, &dstRect);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* complementBytes --
|
|
*
|
|
* For a range of bytes, do an in-place complement. Every bit is inverted.
|
|
*/
|
|
|
|
void
|
|
complementBytes(uint8 *ptr, uint32 count)
|
|
{
|
|
while (count) {
|
|
*ptr ^= 0xFF;
|
|
ptr++;
|
|
count--;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* doBlits --
|
|
*
|
|
* Use screen-to-GMR and GMR-to-screen blits in order to copy from
|
|
* one part of the screen to another. To prove that the guest can
|
|
* access the GMR data, we invert part of the image.
|
|
*/
|
|
|
|
void
|
|
doBlits()
|
|
{
|
|
struct {
|
|
SVGAGMRImageFormat format;
|
|
int screenId;
|
|
int srcx, srcy;
|
|
int dstx, dsty;
|
|
int labelx, labely;
|
|
const char *label;
|
|
} blits[] = {
|
|
/*
|
|
* Copy the red image, using 24-bit color, and label the bottom
|
|
* half (inverse) as Cyan.
|
|
*/
|
|
{
|
|
{{{32, 24}}}, 0,
|
|
319, 19, // src
|
|
134, 19, // dest
|
|
1, 103, // label
|
|
"Cyan",
|
|
},
|
|
|
|
/*
|
|
* Copy the green image using 15-bit color, and label the bottom as pink.
|
|
*/
|
|
{
|
|
{{{16, 15}}}, 0,
|
|
319, 164, // src
|
|
134, 164, // dest
|
|
1, 103, // label
|
|
"Pink",
|
|
},
|
|
|
|
/*
|
|
* Try to copy the blue image. The screen-to-GMR blit will fail, since
|
|
* we don't support screen-to-GMR blits that aren't contained within one
|
|
* screen. So we'll end up drawing gray (the color we clear the buffer with)
|
|
* and a ligher gray on the bottom where we invert.
|
|
*/
|
|
{
|
|
{{{32, 24}}}, 0,
|
|
319, 309, // src
|
|
134, 309, // dest
|
|
1, 1, // label
|
|
"Gray, no cube",
|
|
},
|
|
|
|
/*
|
|
* Now try to copy part of the video overlay from Screen 2.
|
|
* We should get the text and border, but no video.
|
|
*/
|
|
{
|
|
{{{16, 16}}}, 1,
|
|
200, 70, // src
|
|
230, -400, // dest
|
|
0, 0, // label
|
|
"Frame & Text, No Video",
|
|
},
|
|
};
|
|
|
|
const int width = 162;
|
|
const int height = 122;
|
|
const SVGASignedPoint gmrOrigin = { 123, 4 };
|
|
|
|
const int maxBytesPerLine = (width + gmrOrigin.x) * 4;
|
|
const int numBytes = maxBytesPerLine * (height + gmrOrigin.y);
|
|
const int offset = 12345;
|
|
const int numPages = (offset + numBytes + PAGE_MASK) / PAGE_SIZE;
|
|
|
|
const int gmrId = 2;
|
|
PPN firstPage = GMR_DefineContiguous(gmrId, numPages);
|
|
|
|
int i;
|
|
for (i = 0; i < arraysize(blits); i++) {
|
|
|
|
/* Wait for any previous DMA to finish */
|
|
SVGA_SyncToFence(SVGA_InsertFence());
|
|
|
|
/* Clear the buffer to 0x42 (will appear dark grey) */
|
|
memset(PPN_POINTER(firstPage), 0x42, numPages * PAGE_SIZE);
|
|
|
|
SVGAGuestPtr gPtr = { gmrId, offset };
|
|
uint32 bytesPerLine = blits[i].format.bitsPerPixel * width / 8;
|
|
Screen_DefineGMRFB(gPtr, bytesPerLine, blits[i].format);
|
|
|
|
SVGASignedPoint srcPoint = { blits[i].srcx, blits[i].srcy };
|
|
SVGASignedPoint dstPoint = { blits[i].dstx, blits[i].dsty };
|
|
SVGASignedRect srcRect = { srcPoint.x, srcPoint.y,
|
|
srcPoint.x + width, srcPoint.y + height };
|
|
SVGASignedRect dstRect = { dstPoint.x, dstPoint.y,
|
|
dstPoint.x + width, dstPoint.y + height };
|
|
|
|
Screen_BlitToGMRFB(&gmrOrigin, &srcRect, blits[i].screenId);
|
|
|
|
/* Wait for the DMA to finish */
|
|
SVGA_SyncToFence(SVGA_InsertFence());
|
|
|
|
/* Invert the colors in the bottom half of the image */
|
|
uint8 *pixels = (offset +
|
|
bytesPerLine * (gmrOrigin.y + height/2) +
|
|
blits[i].format.bitsPerPixel * gmrOrigin.x / 8 +
|
|
(uint8*)PPN_POINTER(firstPage));
|
|
complementBytes(pixels, bytesPerLine * height/2);
|
|
|
|
/* Copy it back */
|
|
Screen_BlitFromGMRFB(&gmrOrigin, &dstRect, blits[i].screenId);
|
|
|
|
/* Draw a label for the bottom half */
|
|
ScreenDraw_SetScreen(blits[i].screenId, 0, 0);
|
|
Console_MoveTo(dstRect.left + blits[i].labelx, dstRect.top + blits[i].labely);
|
|
Console_WriteString(blits[i].label);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* main --
|
|
*
|
|
* Initialization, main loop.
|
|
*/
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
Intr_Init();
|
|
Intr_SetFaultHandlers(SVGA_DefaultFaultHandler);
|
|
SVGA_Init();
|
|
GMR_Init();
|
|
Heap_Reset();
|
|
SVGA_SetMode(0, 0, 32);
|
|
SVGA3D_Init();
|
|
Screen_Init();
|
|
ScreenDraw_Init(0);
|
|
|
|
initScreens();
|
|
setup3D();
|
|
draw3D();
|
|
initOverlays();
|
|
doBlits();
|
|
cubeLoop();
|
|
|
|
return 0;
|
|
}
|