diff options
author | chai <chaifix@163.com> | 2020-02-22 23:33:06 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2020-02-22 23:33:06 +0800 |
commit | b656c9415a8e7e3b5b7d8bf1f3c8a5444f830c79 (patch) | |
tree | f4f0578d58e5f12b00d2753efef83aaedc03137e /src | |
parent | 9c89460e136ed6c6c43704d9a3a15105e0f006b0 (diff) |
*misc
Diffstat (limited to 'src')
-rw-r--r-- | src/example/03_texture/03_texture.c | 77 | ||||
-rw-r--r-- | src/extend/camera.c | 55 | ||||
-rw-r--r-- | src/extend/camera.h | 35 | ||||
-rw-r--r-- | src/extend/transform.c | 37 | ||||
-rw-r--r-- | src/extend/transform.h | 15 | ||||
-rw-r--r-- | src/extern/wog.c | 81 | ||||
-rw-r--r-- | src/main.c | 28 | ||||
-rw-r--r-- | src/math/math.h | 4 | ||||
-rw-r--r-- | src/math/quat.c | 8 | ||||
-rw-r--r-- | src/math/vec3.c | 12 |
10 files changed, 252 insertions, 100 deletions
diff --git a/src/example/03_texture/03_texture.c b/src/example/03_texture/03_texture.c index f10c41a..352ea9c 100644 --- a/src/example/03_texture/03_texture.c +++ b/src/example/03_texture/03_texture.c @@ -41,9 +41,9 @@ static Texture* cyborg_albedo; static Mesh* cyborg_mesh; void onload_texture(void* data) { - ssr_matrixmode(MATRIX_PROJECTION); - ssr_loadidentity(); - ssr_perspective(90, ssr_getaspect(), 0.1, 10); + //ssr_matrixmode(MATRIX_PROJECTION); + //ssr_loadidentity(); + //ssr_perspective(90, ssr_getaspect(), 0.1, 10); //ssr_ortho(-5, 5, -4, 4, 0.1, 10); ssr_bindvertices(verts, 8, cube, 12); @@ -76,12 +76,12 @@ void onupdate_texture(void*data) { uint dt = *(uint*)data; _t += dt / 1000.f; - ssr_matrixmode(MATRIX_VIEW); - ssr_loadidentity(); - float distance = 2; - Vec3 p = { distance * sin(_t), 5, distance * cos(_t) }, target = { 0, 0, 0 }; - //Vec3 p = { 0, 0, 700}, target = { 0, 0, 0 }; - ssr_lookat(&p, &target, &vec3up); + //ssr_matrixmode(MATRIX_VIEW); + //ssr_loadidentity(); + //float distance = 2; + //Vec3 p = { 0, 0, 10 }, target = { 0, 0, 0 }; + ////Vec3 p = { 0, 0, 700}, target = { 0, 0, 0 }; + //ssr_lookat(&p, &target, &vec3up); ssr_matrixmode(MATRIX_MODEL); ssr_loadidentity(); @@ -103,33 +103,34 @@ void ondraw_texture(void*data) { ssr_clearcolor(0xff202020); ssr_cleardepth(); ssr_clearstencil(0); -///* -// ssr_enable(ENABLE_STENCILTEST); -// ssr_setstencilfunc(STENCILFUNC_ALWAYS, 1, 0xff); -// ssr_setstencilop(STENCILOP_KEEP, STENCILOP_KEEP, STENCILOP_REPLACE); -//*/ -// /*render mech*/ -// ssr_setuniformtex(0, mech_albedo); -// ssr_setuniformtex(1, mech_normal); -// ssr_setuniformtex(2, mech_roughness); -// ssr_setuniformtex(3, mech_metalness); -// ssr_bindvertices(mech_mesh->vertices, mech_mesh->vert_count, mech_mesh->triangles, mech_mesh->tris_count); -// ssr_draw(PRIMITIVE_TRIANGLE); -///* -// ssr_setstencilfunc(STENCILFUNC_EQUAL, 1, 0xff); -// ssr_setstencilop(STENCILOP_KEEP, STENCILOP_KEEP, STENCILOP_KEEP); -//*/ -// /*render yingham*/ -// ssr_setuniformtex(0, yingham_albedo); -// ssr_bindvertices(yingham_mesh->vertices, yingham_mesh->vert_count, yingham_mesh->triangles, yingham_mesh->tris_count); -// ssr_draw(PRIMITIVE_TRIANGLE); -// -// /*render ground*/ -// ssr_setuniformtex(0, ground_albedo); -// ssr_bindvertices(ground_mesh->vertices, ground_mesh->vert_count, ground_mesh->triangles, ground_mesh->tris_count); -// ssr_draw(PRIMITIVE_TRIANGLE); -// - ssr_setuniformtex(0, cyborg_albedo); - ssr_bindvertices(cyborg_mesh->vertices, cyborg_mesh->vert_count, cyborg_mesh->triangles, cyborg_mesh->tris_count); - ssr_draw(PRIMITIVE_TRIANGLE); +/* + ssr_enable(ENABLE_STENCILTEST); + ssr_setstencilfunc(STENCILFUNC_ALWAYS, 1, 0xff); + ssr_setstencilop(STENCILOP_KEEP, STENCILOP_KEEP, STENCILOP_REPLACE); +*/ + /*render mech*/ + ssr_setuniformtex(0, mech_albedo); + ssr_setuniformtex(1, mech_normal); + ssr_setuniformtex(2, mech_roughness); + ssr_setuniformtex(3, mech_metalness); + ssr_bindvertices(mech_mesh->vertices, mech_mesh->vert_count, mech_mesh->triangles, mech_mesh->tris_count); + ssr_draw(PRIMITIVE_TRIANGLE); +/* + ssr_setstencilfunc(STENCILFUNC_EQUAL, 1, 0xff); + ssr_setstencilop(STENCILOP_KEEP, STENCILOP_KEEP, STENCILOP_KEEP); +*/ + /*render yingham*/ + ssr_setuniformtex(0, yingham_albedo); + ssr_bindvertices(yingham_mesh->vertices, yingham_mesh->vert_count, yingham_mesh->triangles, yingham_mesh->tris_count); + ssr_draw(PRIMITIVE_TRIANGLE); + + /*render ground*/ + ssr_setuniformtex(0, ground_albedo); + ssr_bindvertices(ground_mesh->vertices, ground_mesh->vert_count, ground_mesh->triangles, ground_mesh->tris_count); + ssr_draw(PRIMITIVE_TRIANGLE); + + + //ssr_setuniformtex(0, cyborg_albedo); + //ssr_bindvertices(cyborg_mesh->vertices, cyborg_mesh->vert_count, cyborg_mesh->triangles, cyborg_mesh->tris_count); + //ssr_draw(PRIMITIVE_TRIANGLE); } diff --git a/src/extend/camera.c b/src/extend/camera.c index e69de29..377a09e 100644 --- a/src/extend/camera.c +++ b/src/extend/camera.c @@ -0,0 +1,55 @@ +#include "camera.h" + +void camera_init(Camera* cam) { + cam->is_viewdirty = cam->is_projdirty = TRUE; + cam->transform.parent = NULL ; + cam->transform.localposition = vec3_make(0, 0, 800); + cam->transform.localscale = vec3_make(1, 1, 1); + cam->transform.localrotation = quat_make(0, 0, 0); + cam->near = 1; + cam->far = 1500; + cam->aspect = 600/500.f; + cam->fov = 90; + cam->zoom_speed = 20; +} + +void camera_getmatrix(Camera* cam, Mat4* view, Mat4* proj) { + camera_getviewmatrix(cam, view); + camera_getprojmatrix(cam, proj); +} + +void camera_getviewmatrix(Camera* cam, Mat4* out) { + if (!cam->is_viewdirty) { + if (out)*out = cam->view_matrix; + return; + } + transform_getinvmatrixnoscale(&cam->transform, &cam->view_matrix); + if(out) *out = cam->view_matrix; + cam->is_viewdirty = FALSE; +} + +void camera_getprojmatrix(Camera* cam, Mat4* out) { + if (!cam->is_projdirty) { + if (out)*out = cam->proj_matrix; + return; + } + mat4_setperspective(cam->fov, cam->aspect, cam->near, cam->far, &cam->proj_matrix); + if(out) *out = cam->proj_matrix; + cam->is_projdirty = FALSE; +} + +static void _onwheelscroll(Camera* cam, int wheel) { + Quat rot; transform_getrotation(&cam->transform, &rot); + Vec3 forward = {0,0,-1}; + quat_applytovec3(&rot, &forward, &forward); + vec3_scale(&forward, cam->zoom_speed * wheel, &forward); + vec3_plus(&forward, &cam->transform.localposition, &cam->transform.localposition); + cam->is_viewdirty = TRUE; +} + +void camera_onevent(Camera* cam, wog_Event* e) { + if(e == NULL) return ; + if (e->type == WOG_EMOUSEWHEEL) {//zoom in\zoom out + _onwheelscroll(cam, e->wheel); + } +} diff --git a/src/extend/camera.h b/src/extend/camera.h index 2b7afa5..8227dbf 100644 --- a/src/extend/camera.h +++ b/src/extend/camera.h @@ -2,18 +2,37 @@ #define _SOFTSHADEROOM_CAMERA_H_ #include "../math/math.h" +#include "transform.h" +#include "../extern/wog.h" -typedef struct Camera { - Vec3 front; +#undef near +#undef far + +typedef struct { + Transform transform; + float fov, aspect, near, far; + /*matrix*/ + Mat4 view_matrix; /*or WorldToCameraMatrix*/ + Mat4 proj_matrix; + bool is_viewdirty, is_projdirty; + /*operations*/ + float zoom_speed; } Camera; -void camera_onmousemove(float x, float y); -void camera_onleftdown(); -void camera_onleftup(); -void camera_onrightdown(); -void camera_onrightup(); -void camera_onscroll(int amount); +typedef struct CameraConfig { + float fov, aspect, near, far; + Vec3 pos; +}CameraConfig; + +void camera_init(Camera* cam); + +void camera_setposition(float x, float y, float z); + +void camera_onevent(Camera* cam, wog_Event* e); void camera_getmatrix(Mat4* view, Mat4* proj); +void camera_getviewmatrix(Camera* cam, Mat4* view); +void camera_getprojmatrix(Camera* cam, Mat4* proj); + #endif
\ No newline at end of file diff --git a/src/extend/transform.c b/src/extend/transform.c index e69de29..7724614 100644 --- a/src/extend/transform.c +++ b/src/extend/transform.c @@ -0,0 +1,37 @@ +#include "transform.h" + +void transform_getpositionandrotation(Transform* trans, Vec3* pos, Quat* rot) { + *pos = trans->localposition; + *rot = trans->localrotation; + Transform* cur = trans->parent; + while (cur) { + /*按照srt的顺序计算pos*/ + vec3_scale3(pos, &cur->localscale, pos); + quat_applytovec3(&cur->localrotation, pos, pos); + vec3_plus(pos, &cur->localposition, pos); + /*计算旋转*/ + quat_multiply(&cur->localrotation, rot, rot); + + cur = cur->parent; + } +} + +void transform_getinvmatrixnoscale(Transform* trans, Mat4* worldToLocal) { + Vec3 pos; Quat rot; + transform_getpositionandrotation(trans, &pos, &rot); + quat_invert(&rot, &rot); + /*(TR)^-1 = R^-1T^-1*/ + quat_tomat4(&rot, worldToLocal); + vec3_scale(&pos, -1, &pos); + mat4_translate(worldToLocal, &pos, worldToLocal); +} + +void transform_getrotation(Transform* trans, Quat* rot) { + *rot = trans->localrotation; + Transform* cur = trans->parent; + while (cur) { + quat_multiply(&cur->localrotation, rot, rot); + } +} + + diff --git a/src/extend/transform.h b/src/extend/transform.h index 16b7c7f..f647819 100644 --- a/src/extend/transform.h +++ b/src/extend/transform.h @@ -1,5 +1,7 @@ #include "../math/math.h" + +typedef struct Transform Transform; /* ** Transform要注意按 scale -> rotation -> position 顺序计算 */ @@ -13,15 +15,16 @@ typedef struct Transform { Vec3 position; Vec3 scale; Quat rotation; - bool isdirty; } Transform; -void transform_translate(Transform* trans, Vec4* v, Vec4* out); - -Vec4 transform_translate(Transform* trans, Vec4* v); +void transform_translate(Transform* trans, Vec3* v); -void transform_getrotation(Quat* out); /*get global rotation*/ -void transform_getposition(Vec3* out); +void transform_getrotation(Transform* trans, Quat* out); /*get global rotation*/ +void transform_getposition(Transform* trans, Vec3* out); void transform_getscale(Vec3* out); +void transform_getpositionandrotation(Transform* trans, Vec3* pos, Quat* rot); void transform_setdirty(Transform* trans); + +/*get world to local matrix(no scale)*/ +void transform_getinvmatrixnoscale(Transform* transform, Mat4* worldToLocal); diff --git a/src/extern/wog.c b/src/extern/wog.c index 7b8af8d..6cdfb6f 100644 --- a/src/extern/wog.c +++ b/src/extern/wog.c @@ -41,6 +41,7 @@ typedef struct wog_Window { HWND hwnd; // Window handler HDC hdc; // Device Context + HDC mdc; // Memory Device Contexts #if WOG_API == WOG_GDI wog_Surface* surface; // render buffer #endif @@ -280,18 +281,21 @@ static int registerWindowClass() return TRUE; } -static void create_surface(HWND handle, int width, int height, wog_Surface **out_surface, HDC *out_memory_dc) { +/* + * for memory device context, see + * https://docs.microsoft.com/en-us/windows/desktop/gdi/memory-device-contexts + * also + * SDL_windowsframebuffer.c WIN_CreateWindowFramebuffer + */ +static void create_surface(wog_Window* wnd, int width, int height) { BITMAPINFOHEADER bi_header; - HDC window_dc; HDC memory_dc; HBITMAP dib_bitmap; HBITMAP old_bitmap; unsigned char *buffer; // color buffer wog_Surface *surface; - window_dc = GetDC(handle); - memory_dc = CreateCompatibleDC(window_dc); - ReleaseDC(handle, window_dc); + memory_dc = CreateCompatibleDC(wnd->hdc); /*memory device contexts*/ memset(&bi_header, 0, sizeof(BITMAPINFOHEADER)); bi_header.biSize = sizeof(BITMAPINFOHEADER); @@ -300,8 +304,8 @@ static void create_surface(HWND handle, int width, int height, wog_Surface **out bi_header.biPlanes = 1; bi_header.biBitCount = 32; bi_header.biCompression = BI_RGB; - dib_bitmap = CreateDIBSection(memory_dc, (BITMAPINFO*)&bi_header, - DIB_RGB_COLORS, (void**)&buffer, NULL, 0); + /*create bitmap*/ + dib_bitmap = CreateDIBSection(memory_dc, (BITMAPINFO*)&bi_header, DIB_RGB_COLORS, (void**)&buffer, NULL, 0); assert(dib_bitmap != NULL); old_bitmap = (HBITMAP)SelectObject(memory_dc, dib_bitmap); DeleteObject(old_bitmap); @@ -312,8 +316,8 @@ static void create_surface(HWND handle, int width, int height, wog_Surface **out surface->channels = 4; surface->buffer = buffer; - *out_surface = surface; - *out_memory_dc = memory_dc; + wnd->surface = surface; + wnd->mdc = memory_dc; } @@ -342,30 +346,6 @@ wog_Window* wog_createWindow(const char* title, int width, int height, int x, in if (hasbit(flags, WOG_DISABLE)) windowStyle |= WS_DISABLED; DWORD windowExtendedStyle = WS_EX_APPWINDOW; // Define The Window's Extended Style - - PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be - { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, // Version Number - PFD_DRAW_TO_WINDOW | // Format Must Support Window -#if WOG_API == WOG_GL - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL -#endif - PFD_DOUBLEBUFFER, // Must Support Double Buffering - PFD_TYPE_RGBA, // Request An RGBA Format - 32, // Select Our Color Depth - 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // No Alpha Buffer - 0, // Shift Bit Ignored - 0, // No Accumulation Buffer - 0, 0, 0, 0, // Accumulation Bits Ignored - 16, // 16Bit Z-Buffer (Depth Buffer) - 0, // No Stencil Buffer - 0, // No Auxiliary Buffer - PFD_MAIN_PLANE, // Main Drawing Layer - 0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; RECT windowRect = { 0, 0, width, height }; AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle); width = windowRect.right - windowRect.left; @@ -379,7 +359,7 @@ wog_Window* wog_createWindow(const char* title, int width, int height, int x, in width, height, HWND_DESKTOP, 0, - GetModuleHandle(0), + GetModuleHandle(NULL), wnd ); @@ -398,10 +378,31 @@ wog_Window* wog_createWindow(const char* title, int width, int height, int x, in } #if WOG_API == WOG_GDI - create_surface(wnd->hwnd, client_w, client_h, &wnd->surface, &wnd->hdc); + create_surface(wnd, client_w, client_h); #endif #if WOG_API == WOG_GL + PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 32, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 16, // 16Bit Z-Buffer (Depth Buffer) + 0, // No Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; // set pixel format unsigned int pixelformat; pixelformat = ChoosePixelFormat(wnd->hdc, &pfd); @@ -465,13 +466,9 @@ void wog_destroyGLContext(wog_GLContext* cxt) #endif void wog_updateSurface(wog_Window* wnd) { - HDC window_dc = GetDC(wnd->hwnd); - HDC memory_dc = wnd->hdc; - wog_Surface *surface = wnd->surface; - int width = surface->width; - int height = surface->height; - BitBlt(window_dc, 0, 0, width, height, memory_dc, 0, 0, SRCCOPY); - ReleaseDC(wnd->hwnd, window_dc); + if(wnd->surface == NULL) return ; + int width = wnd->surface->width, height = wnd->surface->height; + BitBlt(wnd->hdc, 0, 0, wnd->surface, height, wnd->mdc, 0, 0, SRCCOPY); } void wog_destroyWindow(wog_Window* wnd) @@ -5,9 +5,10 @@ #include "ssr.h" #include "example/example.h" #include "extern/wog.h" +#include "extend/camera.h" #define SCREEN_WIDTH 600 -#define SCREEN_HEIGHT 480 +#define SCREEN_HEIGHT 500 typedef void(*F)(void*); F onload; @@ -27,7 +28,7 @@ SETEXAMPLEF(onevent, i)\ SETEXAMPLEF(onupdate, i) int main(int argc, char* argv[]) { - wog_Window* wnd = wog_createWindow("test", SCREEN_WIDTH, SCREEN_HEIGHT, 500, 500, 0); + wog_Window* wnd = wog_createWindow("Soft Shader Room", SCREEN_WIDTH, SCREEN_HEIGHT, 500, 500, 0); wog_show(wnd); wog_Surface* surface = wog_getsurface(wnd); // ARGB format /* init ssr */ @@ -38,7 +39,10 @@ int main(int argc, char* argv[]) { }; ssr_init(&config); SETEXAMPLE(EXAMPLECUR); - onload(0); + onload(NULL); + /*set up global camera*/ + Camera cam; + camera_init(&cam); /* main loop */ uint prev = wog_tick(); uint dt = 0; @@ -47,6 +51,7 @@ int main(int argc, char* argv[]) { wog_Event e; while (1) { while (wog_pollEvent(wnd, &e)) { + camera_onevent(&cam, &e); if (e.type == WOG_ECLOSE) { goto quit; } else { @@ -65,14 +70,25 @@ int main(int argc, char* argv[]) { } onupdate(&dt); - ondraw(0); + + /*set vp matrix*/ + ssr_matrixmode(MATRIX_PROJECTION); + camera_getprojmatrix(&cam, NULL); + ssr_loadmatrix(&cam.proj_matrix); + ssr_matrixmode(MATRIX_VIEW); + camera_getviewmatrix(&cam, NULL); + ssr_loadmatrix(&cam.view_matrix); + ssr_matrixmode(MATRIX_MODEL); + + ondraw(NULL); + ssr_present(); wog_updateSurface(wnd); - Sleep(1); /*reduce cpu using*/ + //Sleep(1); /*reduce cpu using*/ } quit: wog_destroyWindow(wnd); - return 1; + return 0; } diff --git a/src/math/math.h b/src/math/math.h index 1c65c01..03e156e 100644 --- a/src/math/math.h +++ b/src/math/math.h @@ -159,9 +159,11 @@ extern Vec4 vec4zero; /*(0,0,0)*/ void vec3_tostring(Vec3* v, char buf[]); void vec3_print(Vec3* v); +Vec3 vec3_make(float x, float y, float z); float vec3_intersection(Vec3* v1, Vec3* v2); /*夹角*/ void vec3_projection(Vec3* v1, Vec3* v2, Vec3* out);/*v1在v2上的投影*/ void vec3_scale(Vec3* v, float k, Vec3* out); +void vec3_scale3(Vec3* v, Vec3* scalar, Vec3* out); void vec3_plus(Vec3* v1, Vec3* v2, Vec3* out); void vec3_offset(Vec3* v, float offset, Vec3* out); void vec3_normalize(Vec3* v, Vec3* out); @@ -260,6 +262,8 @@ void mat43_applytovec3(Mat43* m, Vec3* v, Vec4* out); void quat_tostring(Quat* q, char str[]); void quat_print(Quat* q); +Quat quat_make(float rx, float ry, float rz); + void euler_toquat(Euler* e, Quat* out); void euler_deg2rad(Euler* in, Euler* out); void euler_rad2deg(Euler* in, Euler* out); diff --git a/src/math/quat.c b/src/math/quat.c index e68e254..4dedbed 100644 --- a/src/math/quat.c +++ b/src/math/quat.c @@ -69,6 +69,13 @@ void euler_rad2deg(Euler* in, Euler* out) { out->z = degree(in->z); } +Quat quat_make(float rx, float ry, float rz) { + Quat rot; + Euler euler = {rx, ry, rz}; + quat_fromeuler(&euler, &rot); + return rot; +} + void euler_toquat(Euler* euler, Quat* out) { ssr_assert(euler && out); quat_fromeuler(euler, out); @@ -230,6 +237,7 @@ void quat_minus(Quat* q1, Quat* q2, Quat* out) { quat_multiply(q1, &q2i, out); } +/*q1*q2*/ void quat_multiply(Quat* q1, Quat* q2, Quat* out) { ssr_assert(q1 && q2 && out); diff --git a/src/math/vec3.c b/src/math/vec3.c index d2fb652..5d273d8 100644 --- a/src/math/vec3.c +++ b/src/math/vec3.c @@ -16,6 +16,11 @@ void vec3_cross(Vec3* v1, Vec3* v2, Vec3* out) { out->z = v1->x*v2->y - v1->y*v2->x; } +Vec3 vec3_make(float x, float y, float z) { + Vec3 v = {x, y, z}; + return v; +} + void vec3_scale(Vec3* v, float k, Vec3* out) { ssr_assert(v && out); out->x = v->x * k; @@ -23,6 +28,13 @@ void vec3_scale(Vec3* v, float k, Vec3* out) { out->z = v->z * k; } +void vec3_scale3(Vec3* v, Vec3* scalar, Vec3* out) { + ssr_assert(v && scalar && out); + out->x = v->x * scalar->x; + out->y = v->y * scalar->y; + out->z = v->z * scalar->z; +} + void vec3_plus(Vec3* v1, Vec3* v2, Vec3* out) { ssr_assert(v1 && v2 && out); out->x = v1->x + v2->x; |